From 69257d5d6f9c757cfba4447f63336fd14fb4be49 Mon Sep 17 00:00:00 2001 From: Gery Debongnie Date: Fri, 8 Nov 2013 12:32:10 +0100 Subject: [PATCH 001/274] [REF] work in progress. reset graph view to minimal state in addon web_graph bzr revid: ged@openerp.com-20131108113210-aptz2pne05iwca82 --- addons/web_graph/__openerp__.py | 31 - addons/web_graph/static/lib/dropdown.js | 92 - addons/web_graph/static/lib/flotr2/LICENSE | 19 - addons/web_graph/static/lib/flotr2/Makefile | 40 - addons/web_graph/static/lib/flotr2/README.md | 89 - .../web_graph/static/lib/flotr2/dev/notes.txt | 86 - .../static/lib/flotr2/flotr2.examples.min.js | 2 - .../lib/flotr2/flotr2.examples.types.js | 1425 ---- .../static/lib/flotr2/flotr2.ie.min.js | 33 - addons/web_graph/static/lib/flotr2/flotr2.js | 6865 ----------------- .../web_graph/static/lib/flotr2/flotr2.min.js | 27 - addons/web_graph/static/lib/flotr2/js/Axis.js | 303 - .../web_graph/static/lib/flotr2/js/Color.js | 163 - addons/web_graph/static/lib/flotr2/js/DOM.js | 88 - addons/web_graph/static/lib/flotr2/js/Date.js | 207 - .../static/lib/flotr2/js/DefaultOptions.js | 98 - .../static/lib/flotr2/js/EventAdapter.js | 52 - .../web_graph/static/lib/flotr2/js/Flotr.js | 250 - .../web_graph/static/lib/flotr2/js/Graph.js | 745 -- .../web_graph/static/lib/flotr2/js/Series.js | 74 - addons/web_graph/static/lib/flotr2/js/Text.js | 88 - .../static/lib/flotr2/js/plugins/crosshair.js | 84 - .../static/lib/flotr2/js/plugins/download.js | 51 - .../static/lib/flotr2/js/plugins/grid.js | 208 - .../static/lib/flotr2/js/plugins/handles.js | 199 - .../static/lib/flotr2/js/plugins/hit.js | 337 - .../static/lib/flotr2/js/plugins/labels.js | 227 - .../static/lib/flotr2/js/plugins/legend.js | 179 - .../static/lib/flotr2/js/plugins/selection.js | 278 - .../lib/flotr2/js/plugins/spreadsheet.js | 296 - .../static/lib/flotr2/js/plugins/titles.js | 177 - .../static/lib/flotr2/js/types/bars.js | 274 - .../static/lib/flotr2/js/types/bubbles.js | 119 - .../static/lib/flotr2/js/types/candles.js | 127 - .../static/lib/flotr2/js/types/gantt.js | 229 - .../static/lib/flotr2/js/types/lines.js | 275 - .../static/lib/flotr2/js/types/markers.js | 140 - .../static/lib/flotr2/js/types/pie.js | 210 - .../static/lib/flotr2/js/types/points.js | 66 - .../static/lib/flotr2/js/types/radar.js | 60 - .../static/lib/flotr2/js/types/timeline.js | 90 - .../web_graph/static/lib/flotr2/lib/base64.js | 113 - .../static/lib/flotr2/lib/bean-min.js | 10 - .../web_graph/static/lib/flotr2/lib/bean.js | 501 -- .../static/lib/flotr2/lib/canvas2image.js | 198 - .../static/lib/flotr2/lib/canvastext.js | 429 - .../static/lib/flotr2/lib/excanvas.js | 1425 ---- .../static/lib/flotr2/lib/imagediff.js | 343 - .../static/lib/flotr2/lib/jasmine/MIT.LICENSE | 20 - .../lib/flotr2/lib/jasmine/jasmine-html.js | 190 - .../static/lib/flotr2/lib/jasmine/jasmine.css | 166 - .../static/lib/flotr2/lib/jasmine/jasmine.js | 2476 ------ .../flotr2/lib/jasmine/jasmine_favicon.png | Bin 700 -> 0 bytes .../static/lib/flotr2/lib/prototype.js | 4320 ----------- .../static/lib/flotr2/lib/underscore-min.js | 27 - .../static/lib/flotr2/lib/underscore.js | 839 -- .../static/lib/flotr2/lib/yepnope.js | 1 - addons/web_graph/static/src/css/flotr2.css | 69 - addons/web_graph/static/src/css/graph.css | 80 - addons/web_graph/static/src/js/graph.js | 412 +- addons/web_graph/static/src/xml/web_graph.xml | 39 +- 61 files changed, 5 insertions(+), 26056 deletions(-) delete mode 100644 addons/web_graph/static/lib/dropdown.js delete mode 100644 addons/web_graph/static/lib/flotr2/LICENSE delete mode 100644 addons/web_graph/static/lib/flotr2/Makefile delete mode 100644 addons/web_graph/static/lib/flotr2/README.md delete mode 100644 addons/web_graph/static/lib/flotr2/dev/notes.txt delete mode 100644 addons/web_graph/static/lib/flotr2/flotr2.examples.min.js delete mode 100644 addons/web_graph/static/lib/flotr2/flotr2.examples.types.js delete mode 100644 addons/web_graph/static/lib/flotr2/flotr2.ie.min.js delete mode 100644 addons/web_graph/static/lib/flotr2/flotr2.js delete mode 100644 addons/web_graph/static/lib/flotr2/flotr2.min.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/Axis.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/Color.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/DOM.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/Date.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/DefaultOptions.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/EventAdapter.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/Flotr.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/Graph.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/Series.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/Text.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/crosshair.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/download.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/grid.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/handles.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/hit.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/labels.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/legend.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/selection.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/spreadsheet.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/plugins/titles.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/bars.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/bubbles.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/candles.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/gantt.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/lines.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/markers.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/pie.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/points.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/radar.js delete mode 100644 addons/web_graph/static/lib/flotr2/js/types/timeline.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/base64.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/bean-min.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/bean.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/canvas2image.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/canvastext.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/excanvas.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/imagediff.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/jasmine/MIT.LICENSE delete mode 100644 addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine-html.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.css delete mode 100644 addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine_favicon.png delete mode 100644 addons/web_graph/static/lib/flotr2/lib/prototype.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/underscore-min.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/underscore.js delete mode 100644 addons/web_graph/static/lib/flotr2/lib/yepnope.js delete mode 100644 addons/web_graph/static/src/css/flotr2.css diff --git a/addons/web_graph/__openerp__.py b/addons/web_graph/__openerp__.py index c62a1877ee0..8a7baa2bc0a 100644 --- a/addons/web_graph/__openerp__.py +++ b/addons/web_graph/__openerp__.py @@ -15,37 +15,6 @@ Graph Views for Web Client. 'version': '3.0', 'depends': ['web'], 'js': [ - 'static/lib/dropdown.js', - 'static/lib/flotr2/lib/bean.js', - 'static/lib/flotr2/js/Flotr.js', - 'static/lib/flotr2/js/DefaultOptions.js', - 'static/lib/flotr2/js/Color.js', - 'static/lib/flotr2/js/Date.js', - 'static/lib/flotr2/js/DOM.js', - 'static/lib/flotr2/js/EventAdapter.js', - 'static/lib/flotr2/js/Text.js', - 'static/lib/flotr2/js/Graph.js', - 'static/lib/flotr2/js/Axis.js', - 'static/lib/flotr2/js/Series.js', - 'static/lib/flotr2/js/types/lines.js', - 'static/lib/flotr2/js/types/bars.js', - 'static/lib/flotr2/js/types/bubbles.js', - 'static/lib/flotr2/js/types/candles.js', - 'static/lib/flotr2/js/types/gantt.js', - 'static/lib/flotr2/js/types/markers.js', - 'static/lib/flotr2/js/types/pie.js', - 'static/lib/flotr2/js/types/points.js', - 'static/lib/flotr2/js/types/radar.js', - 'static/lib/flotr2/js/types/timeline.js', - 'static/lib/flotr2/js/plugins/crosshair.js', - 'static/lib/flotr2/js/plugins/download.js', - 'static/lib/flotr2/js/plugins/grid.js', - 'static/lib/flotr2/js/plugins/hit.js', - 'static/lib/flotr2/js/plugins/selection.js', - 'static/lib/flotr2/js/plugins/labels.js', - 'static/lib/flotr2/js/plugins/legend.js', - 'static/lib/flotr2/js/plugins/spreadsheet.js', - 'static/lib/flotr2/js/plugins/titles.js', 'static/src/js/graph.js' ], 'css': [ diff --git a/addons/web_graph/static/lib/dropdown.js b/addons/web_graph/static/lib/dropdown.js deleted file mode 100644 index 54b61c5e9d0..00000000000 --- a/addons/web_graph/static/lib/dropdown.js +++ /dev/null @@ -1,92 +0,0 @@ -/* ============================================================ - * bootstrap-dropdown.js v2.0.2 - * http://twitter.github.com/bootstrap/javascript.html#dropdowns - * ============================================================ - * Copyright 2012 Twitter, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============================================================ */ - - -!function( $ ){ - - "use strict" - - /* DROPDOWN CLASS DEFINITION - * ========================= */ - - var toggle = '[data-toggle="dropdown"]' - , Dropdown = function ( element ) { - var $el = $(element).on('click.dropdown.data-api', this.toggle) - $('html').on('click.dropdown.data-api', function () { - $el.parent().removeClass('open') - }) - } - - Dropdown.prototype = { - - constructor: Dropdown - - , toggle: function ( e ) { - var $this = $(this) - , selector = $this.attr('data-target') - , $parent - , isActive - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 - } - - $parent = $(selector) - $parent.length || ($parent = $this.parent()) - - isActive = $parent.hasClass('open') - - clearMenus() - !isActive && $parent.toggleClass('open') - - return false - } - - } - - function clearMenus() { - $(toggle).parent().removeClass('open') - } - - - /* DROPDOWN PLUGIN DEFINITION - * ========================== */ - - $.fn.dropdown = function ( option ) { - return this.each(function () { - var $this = $(this) - , data = $this.data('dropdown') - if (!data) $this.data('dropdown', (data = new Dropdown(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - $.fn.dropdown.Constructor = Dropdown - - - /* APPLY TO STANDARD DROPDOWN ELEMENTS - * =================================== */ - - $(function () { - $('html').on('click.dropdown.data-api', clearMenus) - $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) - }) - -}( window.jQuery ); \ No newline at end of file diff --git a/addons/web_graph/static/lib/flotr2/LICENSE b/addons/web_graph/static/lib/flotr2/LICENSE deleted file mode 100644 index eeb8ce52b3b..00000000000 --- a/addons/web_graph/static/lib/flotr2/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2012 Carl Sutherland - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/addons/web_graph/static/lib/flotr2/Makefile b/addons/web_graph/static/lib/flotr2/Makefile deleted file mode 100644 index 70157b0f3fa..00000000000 --- a/addons/web_graph/static/lib/flotr2/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -all: test flotr2 - -test: - cd spec; jasmine-headless-webkit -j jasmine.yml -c - -libraries: - smoosh make/lib.json - cat ./build/bean.js > build/lib.js - cat ./build/underscore.js >> build/lib.js - cat ./build/bean.min.js > build/lib.min.js - echo ";" >> build/lib.min.js - cat ./build/underscore.min.js >> build/lib.min.js - echo ";" >> build/lib.min.js - -ie: - smoosh make/ie.json - -flotr2: libraries ie - smoosh make/flotr2.json - cat build/lib.js build/flotr2.js > flotr2.js - cat build/lib.min.js > flotr2.min.js - cat build/flotr2.min.js >> flotr2.min.js - echo ';' >> flotr2.min.js - cp build/ie.min.js flotr2.ie.min.js - -flotr2-basic: libraries ie - smoosh make/basic.json - cat build/lib.min.js > flotr2-basic.min.js - cat build/flotr2-basic.min.js >> flotr2-basic.min.js - -flotr2-standalone: ie - smoosh make/flotr2.json - cat build/flotr2.js > flotr2.js - cp build/ie.min.js flotr2.ie.min.js - -flotr-examples: - smoosh make/examples.json - cp build/examples.min.js flotr2.examples.min.js - cp build/examples-types.js flotr2.examples.types.js - diff --git a/addons/web_graph/static/lib/flotr2/README.md b/addons/web_graph/static/lib/flotr2/README.md deleted file mode 100644 index 46f180c0fc6..00000000000 --- a/addons/web_graph/static/lib/flotr2/README.md +++ /dev/null @@ -1,89 +0,0 @@ -Flotr2 -====== - -The Canvas graphing library. - -![Google Groups](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - -http://groups.google.com/group/flotr2/ - -Please fork http://jsfiddle.net/cesutherland/ZFBj5/ with your question or bug reproduction case. - - -API ---- - -The API consists of a primary draw method which accepts a configuration object, helper methods, and several microlibs. - -### Example - -```javascript - var - // Container div: - container = document.getElementById("flotr-example-graph"), - // First data series: - d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], - // Second data series: - d2 = [], - // A couple flotr configuration options: - options = { - xaxis: { - minorTickFreq: 4 - }, - grid: { - minorVerticalLines: true - } - }, - i, graph; - - // Generated second data set: - for (i = 0; i < 14; i += 0.5) { - d2.push([i, Math.sin(i)]); - } - - // Draw the graph: - graph = Flotr.draw( - container, // Container element - [ d1, d2 ], // Array of data series - options // Configuration options - ); -``` - -### Microlibs - -* [underscore.js](http://documentcloud.github.com/underscore/) -* [bean.js](https://github.com/fat/bean) - -Extending ---------- - -Flotr may be extended by adding new plugins and graph types. - -### Graph Types - -Graph types define how a particular chart is rendered. Examples include line, bar, pie. - -Existing graph types are found in `js/types/`. - -### Plugins - -Plugins extend the core of flotr with new functionality. They can add interactions, new decorations, etc. Examples -include titles, labels and selection. - -The plugins included are found in `js/plugins/`. - -Development ------------ - -This project uses [smoosh](https://github.com/fat/smoosh) to build and [jasmine](http://pivotal.github.com/jasmine/) -with [js-imagediff](https://github.com/HumbleSoftware/js-imagediff) to test. Tests may be executed by -[jasmine-headless-webkit](http://johnbintz.github.com/jasmine-headless-webkit/) with -`cd spec; jasmine-headless-webkit -j jasmine.yml -c` or by a browser by navigating to -`flotr2/spec/SpecRunner.html`. - -Shoutouts ---------- - -Thanks to Bas Wenneker, Fabien Ménager and others for all the work on the original Flotr. -Thanks to Jochen Berger and Jordan Santell for their contributions to Flotr2. - diff --git a/addons/web_graph/static/lib/flotr2/dev/notes.txt b/addons/web_graph/static/lib/flotr2/dev/notes.txt deleted file mode 100644 index 982474e579f..00000000000 --- a/addons/web_graph/static/lib/flotr2/dev/notes.txt +++ /dev/null @@ -1,86 +0,0 @@ -Flotr 2 Architecture Notes - - -Global: -====== - -Flotr.js - - versioning information - browser detection - extension (plugins, graph types) - draw - clone / merge - tick size - tick formatter - engineering notation - magnitude - rad, pixel, floor - drawText - measureText - getBestTextAlign - align map - compatibility - - -Graph Architecture: -=================== - -Axis - - all series - orientation - ticks (major, minor) - scale (d2p, p2d, logarithmic) - notion of stacks - -Series - - per 'data' - notion of range (x, y, min, max) - -Graph - - DOM constructon - event attachment - options initialization - data range calculations - canvas spacing calculations - event normalization - draw methods - DOM cleanup - event cleanup - - -Utilities: -========== - -Color - build colors - parse textual color data - convert colors - clone colors - -Text - calculate text size - canvas size - html size - -Date - formatting - constants - - -Spacing Calculation -=================== - -Flotr - calculate data - calculate margins - -Chart - calculate Data Ranges - Explicit or auto data minimum, maximums - calculate Data Range Extensions - By chart type, extend data range with needs of chart type (ie. stacked bars, stacked lines) - add Chart Padding - By chart type - -Text - use explicit margins - calculate label margins - calculate title margins - diff --git a/addons/web_graph/static/lib/flotr2/flotr2.examples.min.js b/addons/web_graph/static/lib/flotr2/flotr2.examples.min.js deleted file mode 100644 index 7bbf25592a3..00000000000 --- a/addons/web_graph/static/lib/flotr2/flotr2.examples.min.js +++ /dev/null @@ -1,2 +0,0 @@ - -(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='
',t='
'+'
View All
'+'
'+'
'+"
";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='
'+'
'+'
'+'
'+"
",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='Error: ',f,g;e+=''+a+"",typeof c!="undefined"&&(e+='',e+='Line '+c+"",console.log(b),b&&(e+=" of ",b==window.location?(e+='script',!d):e+=''+b+""),e+="."),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='
',T_EDITOR='
',T_SOURCE='
',T_ERRORS='
',T_RENDER='
',T_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(""),h;c.each(this.list.getType("profile"),function(e){h=a.node("
  • "+e.name+"
  • "),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='
    Profile started for "'+a.name+'"...
    '},profileEnd:function(a){var b=document.getElementById(e);profileTime=new Date-this._startTime,this._startTime=null,b.innerHTML+="
    Profile complete: "+profileTime+"ms
    "}}),Flotr.Profile=g}() \ No newline at end of file diff --git a/addons/web_graph/static/lib/flotr2/flotr2.examples.types.js b/addons/web_graph/static/lib/flotr2/flotr2.examples.types.js deleted file mode 100644 index f22bc9596f9..00000000000 --- a/addons/web_graph/static/lib/flotr2/flotr2.examples.types.js +++ /dev/null @@ -1,1425 +0,0 @@ -(function () { - -var ExampleList = function () { - - // Map of examples. - this.examples = {}; - -}; - -ExampleList.prototype = { - - add : function (example) { - this.examples[example.key] = example; - }, - - get : function (key) { - return key ? (this.examples[key] || null) : this.examples; - }, - - getType : function (type) { - return Flotr._.select(this.examples, function (example) { - return (example.type === type); - }); - } -} - -Flotr.ExampleList = new ExampleList(); - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic', - name : 'Basic', - callback : basic -}); - -function basic (container) { - - var - d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], // First data series - d2 = [], // Second data series - i, graph; - - // Generate first data set - for (i = 0; i < 14; i += 0.5) { - d2.push([i, Math.sin(i)]); - } - - // Draw Graph - graph = Flotr.draw(container, [ d1, d2 ], { - xaxis: { - minorTickFreq: 4 - }, - grid: { - minorVerticalLines: true - } - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-stacked', - name : 'Basic Stacked', - callback : basic_stacked, - type : 'test' -}); - -function basic_stacked (container) { - - var - d1 = [[0, 3], [4, 8], [8, 2], [9, 3]], // First data series - d2 = [[0, 2], [4, 3], [8, 8], [9, 4]], // Second data series - i, graph; - - // Draw Graph - graph = Flotr.draw(container, [ d1, d2 ], { - lines: { - show : true, - stacked: true - }, - xaxis: { - minorTickFreq: 4 - }, - grid: { - minorVerticalLines: true - } - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-stepped', - name : 'Basic Stepped', - callback : basic_stepped, - type : 'test' -}); - -function basic_stepped (container) { - - var - d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], // First data series - d2 = [], // Second data series - i, graph; - - // Generate first data set - for (i = 0; i < 14; i += 0.5) { - d2.push([i, Math.sin(i)]); - } - - // Draw Graph - graph = Flotr.draw(container, [ d1, d2 ], { - lines: { - steps : true, - show : true - }, - xaxis: { - minorTickFreq: 4 - }, - yaxis: { - autoscale: true - }, - grid: { - minorVerticalLines: true - }, - mouse : { - track : true, - relative : true - } - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-axis', - name : 'Basic Axis', - callback : basic_axis -}); - -function basic_axis (container) { - - var - d1 = [], - d2 = [], - d3 = [], - d4 = [], - d5 = [], // Data - ticks = [[ 0, "Lower"], 10, 20, 30, [40, "Upper"]], // Ticks for the Y-Axis - graph; - - for(var i = 0; i <= 10; i += 0.1){ - d1.push([i, 4 + Math.pow(i,1.5)]); - d2.push([i, Math.pow(i,3)]); - d3.push([i, i*5+3*Math.sin(i*4)]); - d4.push([i, i]); - if( i.toFixed(1)%1 == 0 ){ - d5.push([i, 2*i]); - } - } - - d3[30][1] = null; - d3[31][1] = null; - - function ticksFn (n) { return '('+n+')'; } - - graph = Flotr.draw(container, [ - { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } }, - { data : d2, label : 'y = x^3'}, - { data : d3, label : 'y = 5x + 3sin(4x)'}, - { data : d4, label : 'y = x'}, - { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } } - ], { - xaxis : { - noTicks : 7, // Display 7 ticks. - tickFormatter : ticksFn, // Displays tick values between brackets. - min : 1, // Part of the series is not displayed. - max : 7.5 // Part of the series is not displayed. - }, - yaxis : { - ticks : ticks, // Set Y-Axis ticks - max : 40 // Maximum value along Y-Axis - }, - grid : { - verticalLines : false, - backgroundColor : { - colors : [[0,'#fff'], [1,'#ccc']], - start : 'top', - end : 'bottom' - } - }, - legend : { - position : 'nw' - }, - title : 'Basic Axis example', - subtitle : 'This is a subtitle' - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-bars', - name : 'Basic Bars', - callback : basic_bars -}); - -Flotr.ExampleList.add({ - key : 'basic-bars-horizontal', - name : 'Horizontal Bars', - args : [true], - callback : basic_bars, - tolerance : 5 -}); - -function basic_bars (container, horizontal) { - - var - horizontal = (horizontal ? true : false), // Show horizontal bars - d1 = [], // First data series - d2 = [], // Second data series - point, // Data point variable declaration - i; - - for (i = 0; i < 4; i++) { - - if (horizontal) { - point = [Math.ceil(Math.random()*10), i]; - } else { - point = [i, Math.ceil(Math.random()*10)]; - } - - d1.push(point); - - if (horizontal) { - point = [Math.ceil(Math.random()*10), i+0.5]; - } else { - point = [i+0.5, Math.ceil(Math.random()*10)]; - } - - d2.push(point); - }; - - // Draw the graph - Flotr.draw( - container, - [d1, d2], - { - bars : { - show : true, - horizontal : horizontal, - shadowSize : 0, - barWidth : 0.5 - }, - mouse : { - track : true, - relative : true - }, - yaxis : { - min : 0, - autoscaleMargin : 1 - } - } - ); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-bar-stacked', - name : 'Stacked Bars', - callback : bars_stacked -}); - -Flotr.ExampleList.add({ - key : 'basic-stacked-horizontal', - name : 'Stacked Horizontal Bars', - args : [true], - callback : bars_stacked, - tolerance : 5 -}); - -function bars_stacked (container, horizontal) { - - var - d1 = [], - d2 = [], - d3 = [], - graph, i; - - for (i = -10; i < 10; i++) { - if (horizontal) { - d1.push([Math.random(), i]); - d2.push([Math.random(), i]); - d3.push([Math.random(), i]); - } else { - d1.push([i, Math.random()]); - d2.push([i, Math.random()]); - d3.push([i, Math.random()]); - } - } - - graph = Flotr.draw(container,[ - { data : d1, label : 'Serie 1' }, - { data : d2, label : 'Serie 2' }, - { data : d3, label : 'Serie 3' } - ], { - legend : { - backgroundColor : '#D2E8FF' // Light blue - }, - bars : { - show : true, - stacked : true, - horizontal : horizontal, - barWidth : 0.6, - lineWidth : 1, - shadowSize : 0 - }, - grid : { - verticalLines : horizontal, - horizontalLines : !horizontal - } - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-pie', - name : 'Basic Pie', - callback : basic_pie -}); - -function basic_pie (container) { - - var - d1 = [[0, 4]], - d2 = [[0, 3]], - d3 = [[0, 1.03]], - d4 = [[0, 3.5]], - graph; - - graph = Flotr.draw(container, [ - { data : d1, label : 'Comedy' }, - { data : d2, label : 'Action' }, - { data : d3, label : 'Romance', - pie : { - explode : 50 - } - }, - { data : d4, label : 'Drama' } - ], { - HtmlText : false, - grid : { - verticalLines : false, - horizontalLines : false - }, - xaxis : { showLabels : false }, - yaxis : { showLabels : false }, - pie : { - show : true, - explode : 6 - }, - mouse : { track : true }, - legend : { - position : 'se', - backgroundColor : '#D2E8FF' - } - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-radar', - name : 'Basic Radar', - callback : basic_radar -}); - -function basic_radar (container) { - - // Fill series s1 and s2. - var - s1 = { label : 'Actual', data : [[0, 3], [1, 8], [2, 5], [3, 5], [4, 3], [5, 9]] }, - s2 = { label : 'Target', data : [[0, 8], [1, 7], [2, 8], [3, 2], [4, 4], [5, 7]] }, - graph, ticks; - - // Radar Labels - ticks = [ - [0, "Statutory"], - [1, "External"], - [2, "Videos"], - [3, "Yippy"], - [4, "Management"], - [5, "oops"] - ]; - - // Draw the graph. - graph = Flotr.draw(container, [ s1, s2 ], { - radar : { show : true}, - grid : { circular : true, minorHorizontalLines : true}, - yaxis : { min : 0, max : 10, minorTickFreq : 2}, - xaxis : { ticks : ticks} - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-bubble', - name : 'Basic Bubble', - callback : basic_bubble -}); - -function basic_bubble (container) { - - var - d1 = [], - d2 = [], - point, graph, i; - - for (i = 0; i < 10; i++ ){ - point = [i, Math.ceil(Math.random()*10), Math.ceil(Math.random()*10)]; - d1.push(point); - - point = [i, Math.ceil(Math.random()*10), Math.ceil(Math.random()*10)]; - d2.push(point); - } - - // Draw the graph - graph = Flotr.draw(container, [d1, d2], { - bubbles : { show : true, baseRadius : 5 }, - xaxis : { min : -4, max : 14 }, - yaxis : { min : -4, max : 14 } - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-candle', - name : 'Basic Candle', - callback : basic_candle -}); - -function basic_candle (container) { - - var - d1 = [], - price = 3.206, - graph, - i, a, b, c; - - for (i = 0; i < 50; i++) { - a = Math.random(); - b = Math.random(); - c = (Math.random() * (a + b)) - b; - d1.push([i, price, price + a, price - b, price + c]); - price = price + c; - } - - // Graph - graph = Flotr.draw(container, [ d1 ], { - candles : { show : true, candleWidth : 0.6 }, - xaxis : { noTicks : 10 } - }); -} - -})(); - - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-legend', - name : 'Basic Legend', - callback : basic_legend -}); - -function basic_legend (container) { - - var - d1 = [], - d2 = [], - d3 = [], - data, - graph, i; - - // Data Generation - for (i = 0; i < 15; i += 0.5) { - d1.push([i, i + Math.sin(i+Math.PI)]); - d2.push([i, i]); - d3.push([i, 15-Math.cos(i)]); - } - - data = [ - { data : d1, label :'x + sin(x+π)' }, - { data : d2, label :'x' }, - { data : d3, label :'15 - cos(x)' } - ]; - - - // This function prepend each label with 'y = ' - function labelFn (label) { - return 'y = ' + label; - } - - // Draw graph - graph = Flotr.draw(container, data, { - legend : { - position : 'se', // Position the legend 'south-east'. - labelFormatter : labelFn, // Format the labels. - backgroundColor : '#D2E8FF' // A light blue background color. - }, - HtmlText : false - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'mouse-tracking', - name : 'Mouse Tracking', - callback : mouse_tracking -}); - -function mouse_tracking (container) { - - var - d1 = [], - d2 = [], - d3 = [], - graph, i; - - for (i = 0; i < 20; i += 0.5) { - d1.push([i, 2*i]); - d2.push([i, i*1.5+1.5*Math.sin(i)]); - d3.push([i, 3*Math.cos(i)+10]); - } - - graph = Flotr.draw( - container, - [ - { - data : d1, - mouse : { track : false } // Disable mouse tracking for d1 - }, - d2, - d3 - ], - { - mouse : { - track : true, // Enable mouse tracking - lineColor : 'purple', - relative : true, - position : 'ne', - sensibility : 1, - trackDecimals : 2, - trackFormatter : function (o) { return 'x = ' + o.x +', y = ' + o.y; } - }, - crosshair : { - mode : 'xy' - } - } - ); - -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'mouse-zoom', - name : 'Mouse Zoom', - callback : mouse_zoom, - description : "

    Select an area of the graph to zoom. Click to reset the chart.

    " -}); - -function mouse_zoom (container) { - - var - d1 = [], - d2 = [], - d3 = [], - options, - graph, - i; - - for (i = 0; i < 40; i += 0.5) { - d1.push([i, Math.sin(i)+3*Math.cos(i)]); - d2.push([i, Math.pow(1.1, i)]); - d3.push([i, 40 - i+Math.random()*10]); - } - - options = { - selection : { mode : 'x', fps : 30 }, - title : 'Mouse Zoom' - }; - - // Draw graph with default options, overwriting with passed options - function drawGraph (opts) { - - // Clone the options, so the 'options' variable always keeps intact. - var o = Flotr._.extend(Flotr._.clone(options), opts || {}); - - // Return a new graph. - return Flotr.draw( - container, - [ d1, d2, d3 ], - o - ); - } - - // Actually draw the graph. - graph = drawGraph(); - - // Hook into the 'flotr:select' event. - Flotr.EventAdapter.observe(container, 'flotr:select', function (area) { - - // Draw graph with new area - f = drawGraph({ - xaxis: {min:area.x1, max:area.x2}, - yaxis: {min:area.y1, max:area.y2} - }); - - }); - - // When graph is clicked, draw the graph with default area. - Flotr.EventAdapter.observe(container, 'flotr:click', function () { drawGraph(); }); -}; - -})(); - - -(function () { - -Flotr.ExampleList.add({ - key : 'mouse-drag', - name : 'Mouse Drag', - callback : mouse_drag -}); - -function mouse_drag (container) { - - var - d1 = [], - d2 = [], - d3 = [], - options, - graph, - start, - i; - - for (i = -40; i < 40; i += 0.5) { - d1.push([i, Math.sin(i)+3*Math.cos(i)]); - d2.push([i, Math.pow(1.1, i)]); - d3.push([i, 40 - i+Math.random()*10]); - } - - options = { - xaxis: {min: 0, max: 20}, - title : 'Mouse Drag' - }; - - // Draw graph with default options, overwriting with passed options - function drawGraph (opts) { - - // Clone the options, so the 'options' variable always keeps intact. - var o = Flotr._.extend(Flotr._.clone(options), opts || {}); - - // Return a new graph. - return Flotr.draw( - container, - [ d1, d2, d3 ], - o - ); - } - - graph = drawGraph(); - - function initializeDrag (e) { - start = graph.getEventPosition(e); - Flotr.EventAdapter.observe(document, 'mousemove', move); - Flotr.EventAdapter.observe(document, 'mouseup', stopDrag); - } - - function move (e) { - var - end = graph.getEventPosition(e), - xaxis = graph.axes.x, - offset = start.x - end.x; - - graph = drawGraph({ - xaxis : { - min : xaxis.min + offset, - max : xaxis.max + offset - } - }); - // @todo: refector initEvents in order not to remove other observed events - Flotr.EventAdapter.observe(graph.overlay, 'mousedown', initializeDrag); - } - - function stopDrag () { - Flotr.EventAdapter.stopObserving(document, 'mousemove', move); - } - - Flotr.EventAdapter.observe(graph.overlay, 'mousedown', initializeDrag); - -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-time', - name : 'Basic Time', - callback : basic_time, - description : "

    Select an area of the graph to zoom. Click to reset the chart.

    " -}); - -function basic_time (container) { - - var - d1 = [], - start = new Date("2009/01/01 01:00").getTime(), - options, - graph, - i, x, o; - - for (i = 0; i < 100; i++) { - x = start+(i*1000*3600*24*36.5); - d1.push([x, i+Math.random()*30+Math.sin(i/20+Math.random()*2)*20+Math.sin(i/10+Math.random())*10]); - } - - options = { - xaxis : { - mode : 'time', - labelsAngle : 45 - }, - selection : { - mode : 'x' - }, - HtmlText : false, - title : 'Time' - }; - - // Draw graph with default options, overwriting with passed options - function drawGraph (opts) { - - // Clone the options, so the 'options' variable always keeps intact. - o = Flotr._.extend(Flotr._.clone(options), opts || {}); - - // Return a new graph. - return Flotr.draw( - container, - [ d1 ], - o - ); - } - - graph = drawGraph(); - - Flotr.EventAdapter.observe(container, 'flotr:select', function(area){ - // Draw selected area - graph = drawGraph({ - xaxis : { min : area.x1, max : area.x2, mode : 'time', labelsAngle : 45 }, - yaxis : { min : area.y1, max : area.y2 } - }); - }); - - // When graph is clicked, draw the graph with default area. - Flotr.EventAdapter.observe(container, 'flotr:click', function () { graph = drawGraph(); }); -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'negative-values', - name : 'Negative Values', - callback : negative_values -}); - -function negative_values (container) { - - var - d0 = [], // Line through y = 0 - d1 = [], // Random data presented as a scatter plot. - d2 = [], // A regression line for the scatter. - sx = 0, - sy = 0, - sxy = 0, - sxsq = 0, - xmean, - ymean, - alpha, - beta, - n, x, y; - - for (n = 0; n < 20; n++){ - - x = n; - y = x + Math.random()*8 - 15; - - d0.push([x, 0]); - d1.push([x, y]); - - // Computations used for regression line - sx += x; - sy += y; - sxy += x*y; - sxsq += Math.pow(x,2); - } - - xmean = sx/n; - ymean = sy/n; - beta = ((n*sxy) - (sx*sy))/((n*sxsq)-(Math.pow(sx,2))); - alpha = ymean - (beta * xmean); - - // Compute the regression line. - for (n = 0; n < 20; n++){ - d2.push([n, alpha + beta*n]) - } - - // Draw the graph - graph = Flotr.draw( - container, [ - { data : d0, shadowSize : 0, color : '#545454' }, // Horizontal - { data : d1, label : 'y = x + (Math.random() * 8) - 15', points : { show : true } }, // Scatter - { data : d2, label : 'y = ' + alpha.toFixed(2) + ' + ' + beta.toFixed(2) + '*x' } // Regression - ], - { - legend : { position : 'se', backgroundColor : '#D2E8FF' }, - title : 'Negative Values' - } - ); -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'click-example', - name : 'Click Example', - callback : click_example -}); - -function click_example (container) { - - var - d1 = [[0,0]], // Point at origin - options, - graph; - - options = { - xaxis: {min: 0, max: 15}, - yaxis: {min: 0, max: 15}, - lines: {show: true}, - points: {show: true}, - mouse: {track:true}, - title: 'Click Example' - }; - - graph = Flotr.draw(container, [d1], options); - - // Add a point to the series and redraw the graph - Flotr.EventAdapter.observe(container, 'flotr:click', function(position){ - - // Add a point to the series at the location of the click - d1.push([position.x, position.y]); - - // Sort the series. - d1 = d1.sort(function (a, b) { return a[0] - b[0]; }); - - // Redraw the graph, with the new series. - graph = Flotr.draw(container, [d1], options); - }); -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'download-image', - name : 'Download Image', - callback : download_image, - description : '' + - '
    ' + - '' + - '' + - - '' + - '' + - '' + - '
    ' -}); - -function download_image (container) { - - var - d1 = [], - d2 = [], - d3 = [], - d4 = [], - d5 = [], - graph, - i; - - for (i = 0; i <= 10; i += 0.1) { - d1.push([i, 4 + Math.pow(i,1.5)]); - d2.push([i, Math.pow(i,3)]); - d3.push([i, i*5+3*Math.sin(i*4)]); - d4.push([i, i]); - if( i.toFixed(1)%1 == 0 ){ - d5.push([i, 2*i]); - } - } - - // Draw the graph - graph = Flotr.draw( - container,[ - {data:d1, label:'y = 4 + x^(1.5)', lines:{fill:true}}, - {data:d2, label:'y = x^3', yaxis:2}, - {data:d3, label:'y = 5x + 3sin(4x)'}, - {data:d4, label:'y = x'}, - {data:d5, label:'y = 2x', lines: {show: true}, points: {show: true}} - ],{ - title: 'Download Image Example', - subtitle: 'You can save me as an image', - xaxis:{ - noTicks: 7, // Display 7 ticks. - tickFormatter: function(n){ return '('+n+')'; }, // => displays tick values between brackets. - min: 1, // => part of the series is not displayed. - max: 7.5, // => part of the series is not displayed. - labelsAngle: 45, - title: 'x Axis' - }, - yaxis:{ - ticks: [[0, "Lower"], 10, 20, 30, [40, "Upper"]], - max: 40, - title: 'y = f(x)' - }, - y2axis:{color:'#FF0000', max: 500, title: 'y = x^3'}, - grid:{ - verticalLines: false, - backgroundColor: 'white' - }, - HtmlText: false, - legend: { - position: 'nw' - } - }); - - this.CurrentExample = function (operation) { - - var - format = $('#image-download input:radio[name=format]:checked').val(); - if (Flotr.isIE && Flotr.isIE < 9) { - alert( - "Your browser doesn't allow you to get a bitmap image from the plot, " + - "you can only get a VML image that you can use in Microsoft Office.
    " - ); - } - - if (operation == 'to-image') { - graph.download.saveImage(format, null, null, true) - } else if (operation == 'download') { - graph.download.saveImage(format); - } else if (operation == 'reset') { - graph.download.restoreCanvas(); - } - }; - - return graph; -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'download-data', - name : 'Download Data', - callback : download_data -}); - -function download_data (container) { - - var - d1 = [], - d2 = [], - d3 = [], - d4 = [], - d5 = [], - graph, - i,x; - - for (i = 0; i <= 100; i += 1) { - x = i / 10; - d1.push([x, 4 + Math.pow(x,1.5)]); - d2.push([x, Math.pow(x,3)]); - d3.push([x, i*5+3*Math.sin(x*4)]); - d4.push([x, x]); - if(x%1 === 0 ){ - d5.push([x, 2*x]); - } - } - - // Draw the graph. - graph = Flotr.draw( - container, [ - { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } }, - { data : d2, label : 'y = x^3' }, - { data : d3, label : 'y = 5x + 3sin(4x)' }, - { data : d4, label : 'y = x' }, - { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } } - ],{ - xaxis : { - noTicks : 7, - tickFormatter : function (n) { return '('+n+')'; }, - min: 1, // Part of the series is not displayed. - max: 7.5 - }, - yaxis : { - ticks : [[ 0, "Lower"], 10, 20, 30, [40, "Upper"]], - max : 40 - }, - grid : { - verticalLines : false, - backgroundColor : 'white' - }, - legend : { - position : 'nw' - }, - spreadsheet : { - show : true, - tickFormatter : function (e) { return e+''; } - } - }); -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'advanced-titles', - name : 'Advanced Titles', - callback : advanced_titles -}); - -function advanced_titles (container) { - - var - d1 = [], - d2 = [], - d3 = [], - d4 = [], - d5 = [], - graph, - i; - - for (i = 0; i <= 10; i += 0.1) { - d1.push([i, 4 + Math.pow(i,1.5)]); - d2.push([i, Math.pow(i,3)]); - d3.push([i, i*5+3*Math.sin(i*4)]); - d4.push([i, i]); - if (i.toFixed(1)%1 == 0) { - d5.push([i, 2*i]); - } - } - - // Draw the graph. - graph = Flotr.draw( - container,[ - { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } }, - { data : d2, label : 'y = x^3', yaxis : 2 }, - { data : d3, label : 'y = 5x + 3sin(4x)' }, - { data : d4, label : 'y = x' }, - { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } } - ], { - title : 'Advanced Titles Example', - subtitle : 'You can save me as an image', - xaxis : { - noTicks : 7, - tickFormatter : function (n) { return '('+n+')'; }, - min : 1, - max : 7.5, - labelsAngle : 45, - title : 'x Axis' - }, - yaxis : { - ticks : [[0, "Lower"], 10, 20, 30, [40, "Upper"]], - max : 40, - title : 'y = f(x)' - }, - y2axis : { color : '#FF0000', max : 500, title : 'y = x^3' }, - grid : { - verticalLines : false, - backgroundColor : 'white' - }, - HtmlText : false, - legend : { - position : 'nw' - } - }); -}; - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'color-gradients', - name : 'Color Gradients', - callback : color_gradients -}); - -function color_gradients (container) { - - var - bars = { - data: [], - bars: { - show: true, - barWidth: 0.8, - lineWidth: 0, - fillColor: { - colors: ['#CB4B4B', '#fff'], - start: 'top', - end: 'bottom' - }, - fillOpacity: 0.8 - } - }, markers = { - data: [], - markers: { - show: true, - position: 'ct' - } - }, lines = { - data: [], - lines: { - show: true, - fillColor: ['#00A8F0', '#fff'], - fill: true, - fillOpacity: 1 - } - }, - point, - graph, - i; - - for (i = 0; i < 8; i++) { - point = [i, Math.ceil(Math.random() * 10)]; - bars.data.push(point); - markers.data.push(point); - } - - for (i = -1; i < 9; i += 0.01){ - lines.data.push([i, i*i/8+2]); - } - - graph = Flotr.draw( - container, - [lines, bars, markers], { - yaxis: { - min: 0, - max: 11 - }, - xaxis: { - min: -0.5, - max: 7.5 - }, - grid: { - verticalLines: false, - backgroundColor: ['#fff', '#ccc'] - } - } - ); -}; - -})(); - - -(function () { - -Flotr.ExampleList.add({ - key : 'profile-bars', - name : 'Profile Bars', - type : 'profile', - callback : profile_bars -}); - -/* -Flotr.ExampleList.add({ - key : 'basic-bars-horizontal', - name : 'Horizontal Bars', - args : [true], - callback : basic_bars -}); -*/ - -function profile_bars (container, horizontal) { - - var - horizontal = (horizontal ? true : false), // Show horizontal bars - d1 = [], // First data series - d2 = [], // Second data series - point, // Data point variable declaration - i; - - for (i = 0; i < 5000; i++) { - - if (horizontal) { - point = [Math.ceil(Math.random()*10), i]; - } else { - point = [i, Math.ceil(Math.random()*10)]; - } - - d1.push(point); - - if (horizontal) { - point = [Math.ceil(Math.random()*10), i+0.5]; - } else { - point = [i+0.5, Math.ceil(Math.random()*10)]; - } - - d2.push(point); - }; - - // Draw the graph - Flotr.draw( - container, - [d1, d2], - { - bars : { - show : true, - horizontal : horizontal, - barWidth : 0.5 - }, - mouse : { - track : true, - relative : true - }, - yaxis : { - min : 0, - autoscaleMargin : 1 - } - } - ); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'basic-timeline', - name : 'Basic Timeline', - callback : basic_timeline -}); - -function basic_timeline (container) { - - var - d1 = [[1, 4, 5]], - d2 = [[3.2, 3, 4]], - d3 = [[1.9, 2, 2], [5, 2, 3.3]], - d4 = [[1.55, 1, 9]], - d5 = [[5, 0, 2.3]], - data = [], - timeline = { show : true, barWidth : .5 }, - markers = [], - labels = ['Obama', 'Bush', 'Clinton', 'Palin', 'McCain'], - i, graph, point; - - // Timeline - Flotr._.each([d1, d2, d3, d4, d5], function (d) { - data.push({ - data : d, - timeline : Flotr._.clone(timeline) - }); - }); - - // Markers - Flotr._.each([d1, d2, d3, d4, d5], function (d) { - point = d[0]; - markers.push([point[0], point[1]]); - }); - data.push({ - data: markers, - markers: { - show: true, - position: 'rm', - fontSize: 11, - labelFormatter : function (o) { return labels[o.index]; } - } - }); - - // Draw Graph - graph = Flotr.draw(container, data, { - xaxis: { - noTicks: 3, - tickFormatter: function (x) { - var - x = parseInt(x), - months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; - return months[(x-1)%12]; - } - }, - yaxis: { - showLabels : false - }, - grid: { - horizontalLines : false - } - }); -} - -})(); - -(function () { - -Flotr.ExampleList.add({ - key : 'advanced-markers', - name : 'Advanced Markers', - callback : advanced_markers, - timeout : 150 -}); - -function advanced_markers (container) { - - var - xmark = new Image(), - checkmark = new Image(), - bars = { - data: [], - bars: { - show: true, - barWidth: 0.6, - lineWidth: 0, - fillOpacity: 0.8 - } - }, markers = { - data: [], - markers: { - show: true, - position: 'ct', - labelFormatter: function (o) { - return (o.y >= 5) ? checkmark : xmark; - } - } - }, - flotr = Flotr, - point, - graph, - i; - - - for (i = 0; i < 8; i++) { - point = [i, Math.ceil(Math.random() * 10)]; - bars.data.push(point); - markers.data.push(point); - } - - var runner = function () { - if (!xmark.complete || !checkmark.complete) { - setTimeout(runner, 50); - return; - } - - graph = flotr.draw( - container, - [bars, markers], { - yaxis: { - min: 0, - max: 11 - }, - xaxis: { - min: -0.5, - max: 7.5 - }, - grid: { - verticalLines: false - } - } - ); - } - - xmark.onload = runner; - xmark.src = 'images/xmark.png'; - checkmark.src = 'images/checkmark.png'; -}; - -})(); - diff --git a/addons/web_graph/static/lib/flotr2/flotr2.ie.min.js b/addons/web_graph/static/lib/flotr2/flotr2.ie.min.js deleted file mode 100644 index 0c64520fcb5..00000000000 --- a/addons/web_graph/static/lib/flotr2/flotr2.ie.min.js +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// Known Issues: -// -// * Patterns only support repeat. -// * Radial gradient are not implemented. The VML version of these look very -// different from the canvas one. -// * Clipping paths are not implemented. -// * Coordsize. The width and height attribute have higher priority than the -// width and height style values which isn't correct. -// * Painting mode isn't implemented. -// * Canvas width/height should is using content-box by default. IE in -// Quirks mode will draw the canvas using border-box. Either change your -// doctype to HTML5 -// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) -// or use Box Sizing Behavior from WebFX -// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) -// * Non uniform scaling does not correctly scale strokes. -// * Optimize. There is always room for speed improvements. -// Only add this code if we do not already have a canvas implementation - -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,"&").replace(/"/g,""")}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("')}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')}else if(f instanceof W){if(j&&k){var I=-d.x,J=-d.y;c.push("')}}else{var K=F(b.fillStyle),L=K.color,M=K.alpha*b.globalAlpha;c.push('')}}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','",""),this.element_.insertAdjacentHTML("BeforeEnd",u.join(""))},O.stroke=function(a){var c=[],d=!1,e=10,f=10;c.push("j.x)j.x=l.x;if(i.y==null||l.yj.y)j.y=l.y}}c.push(' ">'),a?R(this,c,i,j):Q(this,c),c.push(""),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(''),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('','',''),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='';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>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>4);do{e=a.charCodeAt(g++)&255;if(e==61)return i;e=b[e]}while(g>2);do{f=a.charCodeAt(g++)&255;if(f==61)return i;f=b[f]}while(g":{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-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 0) { - // remove(el, 't1 t2 t3', fn) or remove(el, 't1 t2 t3') - typeSpec = typeSpec.split(' ') - for (i = typeSpec.length; i--;) - remove(element, typeSpec[i], fn) - return element - } - type = isString && typeSpec.replace(nameRegex, '') - if (type && customEvents[type]) - type = customEvents[type].type - if (!typeSpec || isString) { - // remove(el) or remove(el, t1.ns) or remove(el, .ns) or remove(el, .ns1.ns2.ns3) - if (namespaces = isString && typeSpec.replace(namespaceRegex, '')) - namespaces = namespaces.split('.') - rm(element, type, fn, namespaces) - } else if (typeof typeSpec === 'function') { - // remove(el, fn) - rm(element, null, typeSpec) - } else { - // remove(el, { t1: fn1, t2, fn2 }) - for (k in typeSpec) { - if (typeSpec.hasOwnProperty(k)) - remove(element, k, typeSpec[k]) - } - } - return element - } - - , add = function (element, events, fn, delfn, $) { - var type, types, i, args - , originalFn = fn - , isDel = fn && typeof fn === 'string' - - if (events && !fn && typeof events === 'object') { - for (type in events) { - if (events.hasOwnProperty(type)) - add.apply(this, [ element, type, events[type] ]) - } - } else { - args = arguments.length > 3 ? slice.call(arguments, 3) : [] - types = (isDel ? fn : events).split(' ') - isDel && (fn = del(events, (originalFn = delfn), $)) && (args = slice.call(args, 1)) - // special case for one() - this === ONE && (fn = once(remove, element, events, fn, originalFn)) - for (i = types.length; i--;) addListener(element, types[i], fn, originalFn, args) - } - return element - } - - , one = function () { - return add.apply(ONE, arguments) - } - - , fireListener = W3C_MODEL ? function (isNative, type, element) { - var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents') - evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1) - element.dispatchEvent(evt) - } : function (isNative, type, element) { - element = targetElement(element, isNative) - // if not-native then we're using onpropertychange so we just increment a custom property - isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++ - } - - , fire = function (element, type, args) { - var i, j, l, names, handlers - , types = type.split(' ') - - for (i = types.length; i--;) { - type = types[i].replace(nameRegex, '') - if (names = types[i].replace(namespaceRegex, '')) - names = names.split('.') - if (!names && !args && element[eventSupport]) { - fireListener(nativeEvents[type], type, element) - } else { - // non-native event, either because of a namespace, arguments or a non DOM element - // iterate over all listeners and manually 'fire' - handlers = registry.get(element, type) - args = [false].concat(args) - for (j = 0, l = handlers.length; j < l; j++) { - if (handlers[j].inNamespaces(names)) - handlers[j].handler.apply(element, args) - } - } - } - return element - } - - , clone = function (element, from, type) { - var i = 0 - , handlers = registry.get(from, type) - , l = handlers.length - - for (;i < l; i++) - handlers[i].original && add(element, handlers[i].type, handlers[i].original) - return element - } - - , bean = { - add: add - , one: one - , remove: remove - , clone: clone - , fire: fire - , noConflict: function () { - context[name] = old - return this - } - } - - if (win[attachEvent]) { - // for IE, clean up on unload to avoid leaks - var cleanup = function () { - var i, entries = registry.entries() - for (i in entries) { - if (entries[i].type && entries[i].type !== 'unload') - remove(entries[i].element, entries[i].type) - } - win[detachEvent]('onunload', cleanup) - win.CollectGarbage && win.CollectGarbage() - } - win[attachEvent]('onunload', cleanup) - } - - return bean -}); -// Underscore.js 1.1.7 -// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore is freely distributable under the MIT license. -// Portions of Underscore are inspired or borrowed from Prototype, -// Oliver Steele's Functional, and John Resig's Micro-Templating. -// For all details and documentation: -// http://documentcloud.github.com/underscore - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var slice = ArrayProto.slice, - unshift = ArrayProto.unshift, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { return new wrapper(obj); }; - - // Export the Underscore object for **CommonJS**, with backwards-compatibility - // for the old `require()` API. If we're not in CommonJS, add `_` to the - // global object. - if (typeof module !== 'undefined' && module.exports) { - module.exports = _; - _._ = _; - } else { - // Exported as a string, for Closure Compiler "advanced" mode. - root['_'] = _; - } - - // Current version. - _.VERSION = '1.1.7'; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - for (var key in obj) { - if (hasOwnProperty.call(obj, key)) { - if (iterator.call(context, obj[key], key, obj) === breaker) return; - } - } - } - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results[results.length] = iterator.call(context, value, index, list); - }); - return results; - }; - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. - _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { - var initial = memo !== void 0; - if (obj == null) obj = []; - if (nativeReduce && obj.reduce === nativeReduce) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); - } - each(obj, function(value, index, list) { - if (!initial) { - memo = value; - initial = true; - } else { - memo = iterator.call(context, memo, value, index, list); - } - }); - if (!initial) throw new TypeError("Reduce of empty array with no initial value"); - return memo; - }; - - // The right-associative version of reduce, also known as `foldr`. - // Delegates to **ECMAScript 5**'s native `reduceRight` if available. - _.reduceRight = _.foldr = function(obj, iterator, memo, context) { - if (obj == null) obj = []; - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { - if (context) iterator = _.bind(iterator, context); - return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); - } - var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); - return _.reduce(reversed, iterator, memo, context); - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { - var result; - any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); - each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - each(obj, function(value, index, list) { - if (!iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Determine whether all of the elements match a truth test. - // Delegates to **ECMAScript 5**'s native `every` if available. - // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - var result = true; - if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); - each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; - }); - return result; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator = iterator || _.identity; - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); - each(obj, function(value, index, list) { - if (result |= iterator.call(context, value, index, list)) return breaker; - }); - return !!result; - }; - - // Determine if a given value is included in the array or object using `===`. - // Aliased as `contains`. - _.include = _.contains = function(obj, target) { - var found = false; - if (obj == null) return found; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - any(obj, function(value) { - if (found = value === target) return true; - }); - return found; - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - return _.map(obj, function(value) { - return (method.call ? method || value : value[method]).apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); - }; - - // Return the maximum element or (element-based computation). - _.max = function(obj, iterator, context) { - if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); - var result = {computed : -Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iterator, context) { - if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); - var result = {computed : Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, iterator, context) { - return _.pluck(_.map(obj, function(value, index, list) { - return { - value : value, - criteria : iterator.call(context, value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }), 'value'); - }; - - // Groups the object's values by a criterion produced by an iterator - _.groupBy = function(obj, iterator) { - var result = {}; - each(obj, function(value, index) { - var key = iterator(value, index); - (result[key] || (result[key] = [])).push(value); - }); - return result; - }; - - // Use a comparator function to figure out at what index an object should - // be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iterator) { - iterator || (iterator = _.identity); - var low = 0, high = array.length; - while (low < high) { - var mid = (low + high) >> 1; - iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; - } - return low; - }; - - // Safely convert anything iterable into a real, live array. - _.toArray = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) return iterable.toArray(); - if (_.isArray(iterable)) return slice.call(iterable); - if (_.isArguments(iterable)) return slice.call(iterable); - return _.values(iterable); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - return _.toArray(obj).length; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head`. The **guard** check allows it to work - // with `_.map`. - _.first = _.head = function(array, n, guard) { - return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; - }; - - // Returns everything but the first entry of the array. Aliased as `tail`. - // Especially useful on the arguments object. Passing an **index** will return - // the rest of the values in the array from that index onward. The **guard** - // check allows it to work with `_.map`. - _.rest = _.tail = function(array, index, guard) { - return slice.call(array, (index == null) || guard ? 1 : index); - }; - - // Get the last element of an array. - _.last = function(array) { - return array[array.length - 1]; - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, function(value){ return !!value; }); - }; - - // Return a completely flattened version of an array. - _.flatten = function(array) { - return _.reduce(array, function(memo, value) { - if (_.isArray(value)) return memo.concat(_.flatten(value)); - memo[memo.length] = value; - return memo; - }, []); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted) { - return _.reduce(array, function(memo, el, i) { - if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el; - return memo; - }, []); - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(_.flatten(arguments)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. (Aliased as "intersect" for back-compat.) - _.intersection = _.intersect = function(array) { - var rest = slice.call(arguments, 1); - return _.filter(_.uniq(array), function(item) { - return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; - }); - }); - }; - - // Take the difference between one array and another. - // Only the elements present in just the first array will remain. - _.difference = function(array, other) { - return _.filter(array, function(value){ return !_.include(other, value); }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); - var results = new Array(length); - for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); - return results; - }; - - // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), - // we need this function. Return the position of the first occurrence of an - // item in an array, or -1 if the item is not included in the array. - // Delegates to **ECMAScript 5**'s native `indexOf` if available. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = function(array, item, isSorted) { - if (array == null) return -1; - var i, l; - if (isSorted) { - i = _.sortedIndex(array, item); - return array[i] === item ? i : -1; - } - if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); - for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; - return -1; - }; - - - // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. - _.lastIndexOf = function(array, item) { - if (array == null) return -1; - if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); - var i = array.length; - while (i--) if (array[i] === item) return i; - return -1; - }; - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (arguments.length <= 1) { - stop = start || 0; - start = 0; - } - step = arguments[2] || 1; - - var len = Math.max(Math.ceil((stop - start) / step), 0); - var idx = 0; - var range = new Array(len); - - while(idx < len) { - range[idx++] = start; - start += step; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Binding with arguments is also known as `curry`. - // Delegates to **ECMAScript 5**'s native `Function.bind` if available. - // We check for `func.bind` first, to fail fast when `func` is undefined. - _.bind = function(func, obj) { - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - var args = slice.call(arguments, 2); - return function() { - return func.apply(obj, args.concat(slice.call(arguments))); - }; - }; - - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. - _.bindAll = function(obj) { - var funcs = slice.call(arguments, 1); - if (funcs.length == 0) funcs = _.functions(obj); - each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memo = {}; - hasher || (hasher = _.identity); - return function() { - var key = hasher.apply(this, arguments); - return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); - }; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(func, args); }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Internal function used to implement `_.throttle` and `_.debounce`. - var limit = function(func, wait, debounce) { - var timeout; - return function() { - var context = this, args = arguments; - var throttler = function() { - timeout = null; - func.apply(context, args); - }; - if (debounce) clearTimeout(timeout); - if (debounce || !timeout) timeout = setTimeout(throttler, wait); - }; - }; - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. - _.throttle = function(func, wait) { - return limit(func, wait, false); - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. - _.debounce = function(func, wait) { - return limit(func, wait, true); - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = function(func) { - var ran = false, memo; - return function() { - if (ran) return memo; - ran = true; - return memo = func.apply(this, arguments); - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return function() { - var args = [func].concat(slice.call(arguments)); - return wrapper.apply(this, args); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var funcs = slice.call(arguments); - return function() { - var args = slice.call(arguments); - for (var i = funcs.length - 1; i >= 0; i--) { - args = [funcs[i].apply(this, args)]; - } - return args[0]; - }; - }; - - // Returns a function that will only be executed after being called N times. - _.after = function(times, func) { - return function() { - if (--times < 1) { return func.apply(this, arguments); } - }; - }; - - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); - var keys = []; - for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - return _.map(obj, _.identity); - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = function(obj) { - each(slice.call(arguments, 1), function(source) { - for (var prop in source) { - if (source[prop] !== void 0) obj[prop] = source[prop]; - } - }); - return obj; - }; - - // Fill in a given object with default properties. - _.defaults = function(obj) { - each(slice.call(arguments, 1), function(source) { - for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; - } - }); - return obj; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - // Check object identity. - if (a === b) return true; - // Different types? - var atype = typeof(a), btype = typeof(b); - if (atype != btype) return false; - // Basic equality test (watch out for coercions). - if (a == b) return true; - // One is falsy and the other truthy. - if ((!a && b) || (a && !b)) return false; - // Unwrap any wrapped objects. - if (a._chain) a = a._wrapped; - if (b._chain) b = b._wrapped; - // One of them implements an isEqual()? - if (a.isEqual) return a.isEqual(b); - if (b.isEqual) return b.isEqual(a); - // Check dates' integer values. - if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime(); - // Both are NaN? - if (_.isNaN(a) && _.isNaN(b)) return false; - // Compare regular expressions. - if (_.isRegExp(a) && _.isRegExp(b)) - return a.source === b.source && - a.global === b.global && - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline; - // If a is not an object by this point, we can't handle it. - if (atype !== 'object') return false; - // Check for different array lengths before comparing contents. - if (a.length && (a.length !== b.length)) return false; - // Nothing else worked, deep compare the contents. - var aKeys = _.keys(a), bKeys = _.keys(b); - // Different object sizes? - if (aKeys.length != bKeys.length) return false; - // Recursive comparison of contents. - for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false; - return true; - }; - - // Is a given array or object empty? - _.isEmpty = function(obj) { - if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (hasOwnProperty.call(obj, key)) return false; - return true; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType == 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Is a given variable an arguments object? - _.isArguments = function(obj) { - return !!(obj && hasOwnProperty.call(obj, 'callee')); - }; - - // Is a given value a function? - _.isFunction = function(obj) { - return !!(obj && obj.constructor && obj.call && obj.apply); - }; - - // Is a given value a string? - _.isString = function(obj) { - return !!(obj === '' || (obj && obj.charCodeAt && obj.substr)); - }; - - // Is a given value a number? - _.isNumber = function(obj) { - return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed)); - }; - - // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript - // that does not equal itself. - _.isNaN = function(obj) { - return obj !== obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false; - }; - - // Is a given value a date? - _.isDate = function(obj) { - return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear); - }; - - // Is the given value a regular expression? - _.isRegExp = function(obj) { - return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false)); - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iterators. - _.identity = function(value) { - return value; - }; - - // Run a function **n** times. - _.times = function (n, iterator, context) { - for (var i = 0; i < n; i++) iterator.call(context, i); - }; - - // Add your own custom functions to the Underscore object, ensuring that - // they're correctly added to the OOP wrapper as well. - _.mixin = function(obj) { - each(_.functions(obj), function(name){ - addToWrapper(name, _[name] = obj[name]); - }); - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = idCounter++; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g - }; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - _.template = function(str, data) { - var c = _.templateSettings; - var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + - 'with(obj||{}){__p.push(\'' + - str.replace(/\\/g, '\\\\') - .replace(/'/g, "\\'") - .replace(c.interpolate, function(match, code) { - return "'," + code.replace(/\\'/g, "'") + ",'"; - }) - .replace(c.evaluate || null, function(match, code) { - return "');" + code.replace(/\\'/g, "'") - .replace(/[\r\n\t]/g, ' ') + "__p.push('"; - }) - .replace(/\r/g, '\\r') - .replace(/\n/g, '\\n') - .replace(/\t/g, '\\t') - + "');}return __p.join('');"; - var func = new Function('obj', tmpl); - return data ? func(data) : func; - }; - - // The OOP Wrapper - // --------------- - - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - var wrapper = function(obj) { this._wrapped = obj; }; - - // Expose `wrapper.prototype` as `_.prototype` - _.prototype = wrapper.prototype; - - // Helper function to continue chaining intermediate results. - var result = function(obj, chain) { - return chain ? _(obj).chain() : obj; - }; - - // A method to easily add functions to the OOP wrapper. - var addToWrapper = function(name, func) { - wrapper.prototype[name] = function() { - var args = slice.call(arguments); - unshift.call(args, this._wrapped); - return result(func.apply(_, args), this._chain); - }; - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - wrapper.prototype[name] = function() { - method.apply(this._wrapped, arguments); - return result(this._wrapped, this._chain); - }; - }); - - // Add all accessor Array functions to the wrapper. - each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - wrapper.prototype[name] = function() { - return result(method.apply(this._wrapped, arguments), this._chain); - }; - }); - - // Start chaining a wrapped Underscore object. - wrapper.prototype.chain = function() { - this._chain = true; - return this; - }; - - // Extracts the result from a wrapped and chained object. - wrapper.prototype.value = function() { - return this._wrapped; - }; - -})(); -/** - * Flotr2 (c) 2012 Carl Sutherland - * MIT License - * Special thanks to: - * Flotr: http://code.google.com/p/flotr/ (fork) - * Flot: https://github.com/flot/flot (original fork) - */ -(function () { - -var - global = this, - previousFlotr = this.Flotr, - Flotr; - -Flotr = { - _: _, - bean: bean, - isIphone: /iphone/i.test(navigator.userAgent), - isIE: (navigator.appVersion.indexOf("MSIE") != -1 ? parseFloat(navigator.appVersion.split("MSIE")[1]) : false), - - /** - * An object of the registered graph types. Use Flotr.addType(type, object) - * to add your own type. - */ - graphTypes: {}, - - /** - * The list of the registered plugins - */ - plugins: {}, - - /** - * Can be used to add your own chart type. - * @param {String} name - Type of chart, like 'pies', 'bars' etc. - * @param {String} graphType - The object containing the basic drawing functions (draw, etc) - */ - addType: function(name, graphType){ - Flotr.graphTypes[name] = graphType; - Flotr.defaultOptions[name] = graphType.options || {}; - Flotr.defaultOptions.defaultType = Flotr.defaultOptions.defaultType || name; - }, - - /** - * Can be used to add a plugin - * @param {String} name - The name of the plugin - * @param {String} plugin - The object containing the plugin's data (callbacks, options, function1, function2, ...) - */ - addPlugin: function(name, plugin){ - Flotr.plugins[name] = plugin; - Flotr.defaultOptions[name] = plugin.options || {}; - }, - - /** - * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha. - * You could also draw graphs by directly calling Flotr.Graph(element, data, options). - * @param {Element} el - element to insert the graph into - * @param {Object} data - an array or object of dataseries - * @param {Object} options - an object containing options - * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph - * @return {Object} returns a new graph object and of course draws the graph. - */ - draw: function(el, data, options, GraphKlass){ - GraphKlass = GraphKlass || Flotr.Graph; - return new GraphKlass(el, data, options); - }, - - /** - * Recursively merges two objects. - * @param {Object} src - source object (likely the object with the least properties) - * @param {Object} dest - destination object (optional, object with the most properties) - * @return {Object} recursively merged Object - * @TODO See if we can't remove this. - */ - merge: function(src, dest){ - var i, v, result = dest || {}; - - for (i in src) { - v = src[i]; - if (v && typeof(v) === 'object') { - if (v.constructor === Array) { - result[i] = this._.clone(v); - } else if (v.constructor !== RegExp && !this._.isElement(v)) { - result[i] = Flotr.merge(v, (dest ? dest[i] : undefined)); - } else { - result[i] = v; - } - } else { - result[i] = v; - } - } - - return result; - }, - - /** - * Recursively clones an object. - * @param {Object} object - The object to clone - * @return {Object} the clone - * @TODO See if we can't remove this. - */ - clone: function(object){ - return Flotr.merge(object, {}); - }, - - /** - * Function calculates the ticksize and returns it. - * @param {Integer} noTicks - number of ticks - * @param {Integer} min - lower bound integer value for the current axis - * @param {Integer} max - upper bound integer value for the current axis - * @param {Integer} decimals - number of decimals for the ticks - * @return {Integer} returns the ticksize in pixels - */ - getTickSize: function(noTicks, min, max, decimals){ - var delta = (max - min) / noTicks, - magn = Flotr.getMagnitude(delta), - tickSize = 10, - norm = delta / magn; // Norm is between 1.0 and 10.0. - - if(norm < 1.5) tickSize = 1; - else if(norm < 2.25) tickSize = 2; - else if(norm < 3) tickSize = ((decimals === 0) ? 2 : 2.5); - else if(norm < 7.5) tickSize = 5; - - return tickSize * magn; - }, - - /** - * Default tick formatter. - * @param {String, Integer} val - tick value integer - * @param {Object} axisOpts - the axis' options - * @return {String} formatted tick string - */ - defaultTickFormatter: function(val, axisOpts){ - return val+''; - }, - - /** - * Formats the mouse tracker values. - * @param {Object} obj - Track value Object {x:..,y:..} - * @return {String} Formatted track string - */ - defaultTrackFormatter: function(obj){ - return '('+obj.x+', '+obj.y+')'; - }, - - /** - * Utility function to convert file size values in bytes to kB, MB, ... - * @param value {Number} - The value to convert - * @param precision {Number} - The number of digits after the comma (default: 2) - * @param base {Number} - The base (default: 1000) - */ - engineeringNotation: function(value, precision, base){ - var sizes = ['Y','Z','E','P','T','G','M','k',''], - fractionSizes = ['y','z','a','f','p','n','µ','m',''], - total = sizes.length; - - base = base || 1000; - precision = Math.pow(10, precision || 2); - - if (value === 0) return 0; - - if (value > 1) { - while (total-- && (value >= base)) value /= base; - } - else { - sizes = fractionSizes; - total = sizes.length; - while (total-- && (value < 1)) value *= base; - } - - return (Math.round(value * precision) / precision) + sizes[total]; - }, - - /** - * Returns the magnitude of the input value. - * @param {Integer, Float} x - integer or float value - * @return {Integer, Float} returns the magnitude of the input value - */ - getMagnitude: function(x){ - return Math.pow(10, Math.floor(Math.log(x) / Math.LN10)); - }, - toPixel: function(val){ - return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val); - }, - toRad: function(angle){ - return -angle * (Math.PI/180); - }, - floorInBase: function(n, base) { - return base * Math.floor(n / base); - }, - drawText: function(ctx, text, x, y, style) { - if (!ctx.fillText) { - ctx.drawText(text, x, y, style); - return; - } - - style = this._.extend({ - size: Flotr.defaultOptions.fontSize, - color: '#000000', - textAlign: 'left', - textBaseline: 'bottom', - weight: 1, - angle: 0 - }, style); - - ctx.save(); - ctx.translate(x, y); - ctx.rotate(style.angle); - ctx.fillStyle = style.color; - ctx.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif"; - ctx.textAlign = style.textAlign; - ctx.textBaseline = style.textBaseline; - ctx.fillText(text, 0, 0); - ctx.restore(); - }, - getBestTextAlign: function(angle, style) { - style = style || {textAlign: 'center', textBaseline: 'middle'}; - angle += Flotr.getTextAngleFromAlign(style); - - if (Math.abs(Math.cos(angle)) > 10e-3) - style.textAlign = (Math.cos(angle) > 0 ? 'right' : 'left'); - - if (Math.abs(Math.sin(angle)) > 10e-3) - style.textBaseline = (Math.sin(angle) > 0 ? 'top' : 'bottom'); - - return style; - }, - alignTable: { - 'right middle' : 0, - 'right top' : Math.PI/4, - 'center top' : Math.PI/2, - 'left top' : 3*(Math.PI/4), - 'left middle' : Math.PI, - 'left bottom' : -3*(Math.PI/4), - 'center bottom': -Math.PI/2, - 'right bottom' : -Math.PI/4, - 'center middle': 0 - }, - getTextAngleFromAlign: function(style) { - return Flotr.alignTable[style.textAlign+' '+style.textBaseline] || 0; - }, - noConflict : function () { - global.Flotr = previousFlotr; - return this; - } -}; - -global.Flotr = Flotr; - -})(); - -/** - * Flotr Defaults - */ -Flotr.defaultOptions = { - colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated. - ieBackgroundColor: '#FFFFFF', // Background color for excanvas clipping - title: null, // => The graph's title - subtitle: null, // => The graph's subtitle - shadowSize: 4, // => size of the 'fake' shadow - defaultType: null, // => default series type - HtmlText: true, // => wether to draw the text using HTML or on the canvas - fontColor: '#545454', // => default font color - fontSize: 7.5, // => canvas' text font size - resolution: 1, // => resolution of the graph, to have printer-friendly graphs ! - parseFloat: true, // => whether to preprocess data for floats (ie. if input is string) - xaxis: { - ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] - minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] - showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise - showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide - labelsAngle: 0, // => labels' angle, in degrees - title: null, // => axis title - titleAngle: 0, // => axis title's angle, in degrees - noTicks: 5, // => number of ticks for automagically generated ticks - minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks - tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string - tickDecimals: null, // => no. of decimals, null means auto - min: null, // => min. value to show, null means set automatically - max: null, // => max. value to show, null means set automatically - autoscale: false, // => Turns autoscaling on with true - autoscaleMargin: 0, // => margin in % to add if auto-setting min/max - color: null, // => color of the ticks - mode: 'normal', // => can be 'time' or 'normal' - timeFormat: null, - timeMode:'UTC', // => For UTC time ('local' for local time). - timeUnit:'millisecond',// => Unit for time (millisecond, second, minute, hour, day, month, year) - scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' - base: Math.E, - titleAlign: 'center', - margin: true // => Turn off margins with false - }, - x2axis: {}, - yaxis: { - ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] - minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] - showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise - showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide - labelsAngle: 0, // => labels' angle, in degrees - title: null, // => axis title - titleAngle: 90, // => axis title's angle, in degrees - noTicks: 5, // => number of ticks for automagically generated ticks - minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks - tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string - tickDecimals: null, // => no. of decimals, null means auto - min: null, // => min. value to show, null means set automatically - max: null, // => max. value to show, null means set automatically - autoscale: false, // => Turns autoscaling on with true - autoscaleMargin: 0, // => margin in % to add if auto-setting min/max - color: null, // => The color of the ticks - scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' - base: Math.E, - titleAlign: 'center', - margin: true // => Turn off margins with false - }, - y2axis: { - titleAngle: 270 - }, - grid: { - color: '#545454', // => primary color used for outline and labels - backgroundColor: null, // => null for transparent, else color - backgroundImage: null, // => background image. String or object with src, left and top - watermarkAlpha: 0.4, // => - tickColor: '#DDDDDD', // => color used for the ticks - labelMargin: 3, // => margin in pixels - verticalLines: true, // => whether to show gridlines in vertical direction - minorVerticalLines: null, // => whether to show gridlines for minor ticks in vertical dir. - horizontalLines: true, // => whether to show gridlines in horizontal direction - minorHorizontalLines: null, // => whether to show gridlines for minor ticks in horizontal dir. - outlineWidth: 1, // => width of the grid outline/border in pixels - outline : 'nsew', // => walls of the outline to display - circular: false // => if set to true, the grid will be circular, must be used when radars are drawn - }, - mouse: { - track: false, // => true to track the mouse, no tracking otherwise - trackAll: false, - position: 'se', // => position of the value box (default south-east) - relative: false, // => next to the mouse cursor - trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box - margin: 5, // => margin in pixels of the valuebox - lineColor: '#FF3F19', // => line color of points that are drawn when mouse comes near a value of a series - trackDecimals: 1, // => decimals for the track values - sensibility: 2, // => the lower this number, the more precise you have to aim to show a value - trackY: true, // => whether or not to track the mouse in the y axis - radius: 3, // => radius of the track point - fillColor: null, // => color to fill our select bar with only applies to bar and similar graphs (only bars for now) - fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - } -}; - -/** - * Flotr Color - */ - -(function () { - -var - _ = Flotr._; - -// Constructor -function Color (r, g, b, a) { - this.rgba = ['r','g','b','a']; - var x = 4; - while(-1<--x){ - this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0); - } - this.normalize(); -} - -// Constants -var COLOR_NAMES = { - aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255], - brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169], - darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47], - darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122], - darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130], - khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144], - lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255], - maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128], - violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0] -}; - -Color.prototype = { - scale: function(rf, gf, bf, af){ - var x = 4; - while (-1 < --x) { - if (!_.isUndefined(arguments[x])) this[this.rgba[x]] *= arguments[x]; - } - return this.normalize(); - }, - alpha: function(alpha) { - if (!_.isUndefined(alpha) && !_.isNull(alpha)) { - this.a = alpha; - } - return this.normalize(); - }, - clone: function(){ - return new Color(this.r, this.b, this.g, this.a); - }, - limit: function(val,minVal,maxVal){ - return Math.max(Math.min(val, maxVal), minVal); - }, - normalize: function(){ - var limit = this.limit; - this.r = limit(parseInt(this.r, 10), 0, 255); - this.g = limit(parseInt(this.g, 10), 0, 255); - this.b = limit(parseInt(this.b, 10), 0, 255); - this.a = limit(this.a, 0, 1); - return this; - }, - distance: function(color){ - if (!color) return; - color = new Color.parse(color); - var dist = 0, x = 3; - while(-1<--x){ - dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]); - } - return dist; - }, - toString: function(){ - return (this.a >= 1.0) ? 'rgb('+[this.r,this.g,this.b].join(',')+')' : 'rgba('+[this.r,this.g,this.b,this.a].join(',')+')'; - }, - contrast: function () { - var - test = 1 - ( 0.299 * this.r + 0.587 * this.g + 0.114 * this.b) / 255; - return (test < 0.5 ? '#000000' : '#ffffff'); - } -}; - -_.extend(Color, { - /** - * Parses a color string and returns a corresponding Color. - * The different tests are in order of probability to improve speed. - * @param {String, Color} str - string thats representing a color - * @return {Color} returns a Color object or false - */ - parse: function(color){ - if (color instanceof Color) return color; - - var result; - - // #a0b1c2 - if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))) - return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)); - - // rgb(num,num,num) - if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))) - return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10)); - - // #fff - if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))) - return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)); - - // rgba(num,num,num,num) - 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))) - return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10), parseFloat(result[4])); - - // rgb(num%,num%,num%) - if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))) - return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55); - - // rgba(num%,num%,num%,num) - 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))) - return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4])); - - // Otherwise, we're most likely dealing with a named color. - var name = (color+'').replace(/^\s*([\S\s]*?)\s*$/, '$1').toLowerCase(); - if(name == 'transparent'){ - return new Color(255, 255, 255, 0); - } - return (result = COLOR_NAMES[name]) ? new Color(result[0], result[1], result[2]) : new Color(0, 0, 0, 0); - }, - - /** - * Process color and options into color style. - */ - processColor: function(color, options) { - - var opacity = options.opacity; - if (!color) return 'rgba(0, 0, 0, 0)'; - if (color instanceof Color) return color.alpha(opacity).toString(); - if (_.isString(color)) return Color.parse(color).alpha(opacity).toString(); - - var grad = color.colors ? color : {colors: color}; - - if (!options.ctx) { - if (!_.isArray(grad.colors)) return 'rgba(0, 0, 0, 0)'; - return Color.parse(_.isArray(grad.colors[0]) ? grad.colors[0][1] : grad.colors[0]).alpha(opacity).toString(); - } - grad = _.extend({start: 'top', end: 'bottom'}, grad); - - if (/top/i.test(grad.start)) options.x1 = 0; - if (/left/i.test(grad.start)) options.y1 = 0; - if (/bottom/i.test(grad.end)) options.x2 = 0; - if (/right/i.test(grad.end)) options.y2 = 0; - - var i, c, stop, gradient = options.ctx.createLinearGradient(options.x1, options.y1, options.x2, options.y2); - for (i = 0; i < grad.colors.length; i++) { - c = grad.colors[i]; - if (_.isArray(c)) { - stop = c[0]; - c = c[1]; - } - else stop = i / (grad.colors.length-1); - gradient.addColorStop(stop, Color.parse(c).alpha(opacity)); - } - return gradient; - } -}); - -Flotr.Color = Color; - -})(); - -/** - * Flotr Date - */ -Flotr.Date = { - - set : function (date, name, mode, value) { - mode = mode || 'UTC'; - name = 'set' + (mode === 'UTC' ? 'UTC' : '') + name; - date[name](value); - }, - - get : function (date, name, mode) { - mode = mode || 'UTC'; - name = 'get' + (mode === 'UTC' ? 'UTC' : '') + name; - return date[name](); - }, - - format: function(d, format, mode) { - if (!d) return; - - // We should maybe use an "official" date format spec, like PHP date() or ColdFusion - // http://fr.php.net/manual/en/function.date.php - // http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_c-d_29.html - var - get = this.get, - tokens = { - h: get(d, 'Hours', mode).toString(), - H: leftPad(get(d, 'Hours', mode)), - M: leftPad(get(d, 'Minutes', mode)), - S: leftPad(get(d, 'Seconds', mode)), - s: get(d, 'Milliseconds', mode), - d: get(d, 'Date', mode).toString(), - m: (get(d, 'Month') + 1).toString(), - y: get(d, 'FullYear').toString(), - b: Flotr.Date.monthNames[get(d, 'Month', mode)] - }; - - function leftPad(n){ - n += ''; - return n.length == 1 ? "0" + n : n; - } - - var r = [], c, - escape = false; - - for (var i = 0; i < format.length; ++i) { - c = format.charAt(i); - - if (escape) { - r.push(tokens[c] || c); - escape = false; - } - else if (c == "%") - escape = true; - else - r.push(c); - } - return r.join(''); - }, - getFormat: function(time, span) { - var tu = Flotr.Date.timeUnits; - if (time < tu.second) return "%h:%M:%S.%s"; - else if (time < tu.minute) return "%h:%M:%S"; - else if (time < tu.day) return (span < 2 * tu.day) ? "%h:%M" : "%b %d %h:%M"; - else if (time < tu.month) return "%b %d"; - else if (time < tu.year) return (span < tu.year) ? "%b" : "%b %y"; - else return "%y"; - }, - formatter: function (v, axis) { - var - options = axis.options, - scale = Flotr.Date.timeUnits[options.timeUnit], - d = new Date(v * scale); - - // first check global format - if (axis.options.timeFormat) - return Flotr.Date.format(d, options.timeFormat, options.timeMode); - - var span = (axis.max - axis.min) * scale, - t = axis.tickSize * Flotr.Date.timeUnits[axis.tickUnit]; - - return Flotr.Date.format(d, Flotr.Date.getFormat(t, span), options.timeMode); - }, - generator: function(axis) { - - var - set = this.set, - get = this.get, - timeUnits = this.timeUnits, - spec = this.spec, - options = axis.options, - mode = options.timeMode, - scale = timeUnits[options.timeUnit], - min = axis.min * scale, - max = axis.max * scale, - delta = (max - min) / options.noTicks, - ticks = [], - tickSize = axis.tickSize, - tickUnit, - formatter, i; - - // Use custom formatter or time tick formatter - formatter = (options.tickFormatter === Flotr.defaultTickFormatter ? - this.formatter : options.tickFormatter - ); - - for (i = 0; i < spec.length - 1; ++i) { - var d = spec[i][0] * timeUnits[spec[i][1]]; - if (delta < (d + spec[i+1][0] * timeUnits[spec[i+1][1]]) / 2 && d >= tickSize) - break; - } - tickSize = spec[i][0]; - tickUnit = spec[i][1]; - - // special-case the possibility of several years - if (tickUnit == "year") { - tickSize = Flotr.getTickSize(options.noTicks*timeUnits.year, min, max, 0); - - // Fix for 0.5 year case - if (tickSize == 0.5) { - tickUnit = "month"; - tickSize = 6; - } - } - - axis.tickUnit = tickUnit; - axis.tickSize = tickSize; - - var - d = new Date(min); - - var step = tickSize * timeUnits[tickUnit]; - - function setTick (name) { - set(d, name, mode, Flotr.floorInBase( - get(d, name, mode), tickSize - )); - } - - switch (tickUnit) { - case "millisecond": setTick('Milliseconds'); break; - case "second": setTick('Seconds'); break; - case "minute": setTick('Minutes'); break; - case "hour": setTick('Hours'); break; - case "month": setTick('Month'); break; - case "year": setTick('FullYear'); break; - } - - // reset smaller components - if (step >= timeUnits.second) set(d, 'Milliseconds', mode, 0); - if (step >= timeUnits.minute) set(d, 'Seconds', mode, 0); - if (step >= timeUnits.hour) set(d, 'Minutes', mode, 0); - if (step >= timeUnits.day) set(d, 'Hours', mode, 0); - if (step >= timeUnits.day * 4) set(d, 'Date', mode, 1); - if (step >= timeUnits.year) set(d, 'Month', mode, 0); - - var carry = 0, v = NaN, prev; - do { - prev = v; - v = d.getTime(); - ticks.push({ v: v / scale, label: formatter(v / scale, axis) }); - if (tickUnit == "month") { - if (tickSize < 1) { - /* a bit complicated - we'll divide the month up but we need to take care of fractions - so we don't end up in the middle of a day */ - set(d, 'Date', mode, 1); - var start = d.getTime(); - set(d, 'Month', mode, get(d, 'Month', mode) + 1) - var end = d.getTime(); - d.setTime(v + carry * timeUnits.hour + (end - start) * tickSize); - carry = get(d, 'Hours', mode) - set(d, 'Hours', mode, 0); - } - else - set(d, 'Month', mode, get(d, 'Month', mode) + tickSize); - } - else if (tickUnit == "year") { - set(d, 'FullYear', mode, get(d, 'FullYear', mode) + tickSize); - } - else - d.setTime(v + step); - - } while (v < max && v != prev); - - return ticks; - }, - timeUnits: { - millisecond: 1, - second: 1000, - minute: 1000 * 60, - hour: 1000 * 60 * 60, - day: 1000 * 60 * 60 * 24, - month: 1000 * 60 * 60 * 24 * 30, - year: 1000 * 60 * 60 * 24 * 365.2425 - }, - // the allowed tick sizes, after 1 year we use an integer algorithm - spec: [ - [1, "millisecond"], [20, "millisecond"], [50, "millisecond"], [100, "millisecond"], [200, "millisecond"], [500, "millisecond"], - [1, "second"], [2, "second"], [5, "second"], [10, "second"], [30, "second"], - [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], [30, "minute"], - [1, "hour"], [2, "hour"], [4, "hour"], [8, "hour"], [12, "hour"], - [1, "day"], [2, "day"], [3, "day"], - [0.25, "month"], [0.5, "month"], [1, "month"], [2, "month"], [3, "month"], [6, "month"], - [1, "year"] - ], - monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] -}; - -(function () { - -var _ = Flotr._; - -Flotr.DOM = { - addClass: function(element, name){ - var classList = (element.className ? element.className : ''); - if (_.include(classList.split(/\s+/g), name)) return; - element.className = (classList ? classList + ' ' : '') + name; - }, - /** - * Create an element. - */ - create: function(tag){ - return document.createElement(tag); - }, - node: function(html) { - var div = Flotr.DOM.create('div'), n; - div.innerHTML = html; - n = div.children[0]; - div.innerHTML = ''; - return n; - }, - /** - * Remove all children. - */ - empty: function(element){ - element.innerHTML = ''; - /* - if (!element) return; - _.each(element.childNodes, function (e) { - Flotr.DOM.empty(e); - element.removeChild(e); - }); - */ - }, - hide: function(element){ - Flotr.DOM.setStyles(element, {display:'none'}); - }, - /** - * Insert a child. - * @param {Element} element - * @param {Element|String} Element or string to be appended. - */ - insert: function(element, child){ - if(_.isString(child)) - element.innerHTML += child; - else if (_.isElement(child)) - element.appendChild(child); - }, - // @TODO find xbrowser implementation - opacity: function(element, opacity) { - element.style.opacity = opacity; - }, - position: function(element, p){ - if (!element.offsetParent) - return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)}; - - p = this.position(element.offsetParent); - p.left += element.offsetLeft; - p.top += element.offsetTop; - return p; - }, - removeClass: function(element, name) { - var classList = (element.className ? element.className : ''); - element.className = _.filter(classList.split(/\s+/g), function (c) { - if (c != name) return true; } - ).join(' '); - }, - setStyles: function(element, o) { - _.each(o, function (value, key) { - element.style[key] = value; - }); - }, - show: function(element){ - Flotr.DOM.setStyles(element, {display:''}); - }, - /** - * Return element size. - */ - size: function(element){ - return { - height : element.offsetHeight, - width : element.offsetWidth }; - } -}; - -})(); - -/** - * Flotr Event Adapter - */ -(function () { -var - F = Flotr, - bean = F.bean; -F.EventAdapter = { - observe: function(object, name, callback) { - bean.add(object, name, callback); - return this; - }, - fire: function(object, name, args) { - bean.fire(object, name, args); - if (typeof(Prototype) != 'undefined') - Event.fire(object, name, args); - // @TODO Someone who uses mootools, add mootools adapter for existing applciations. - return this; - }, - stopObserving: function(object, name, callback) { - bean.remove(object, name, callback); - return this; - }, - eventPointer: function(e) { - if (!F._.isUndefined(e.touches) && e.touches.length > 0) { - return { - x : e.touches[0].pageX, - y : e.touches[0].pageY - }; - } else if (!F._.isUndefined(e.changedTouches) && e.changedTouches.length > 0) { - return { - x : e.changedTouches[0].pageX, - y : e.changedTouches[0].pageY - }; - } else if (e.pageX || e.pageY) { - return { - x : e.pageX, - y : e.pageY - }; - } else if (e.clientX || e.clientY) { - var - d = document, - b = d.body, - de = d.documentElement; - return { - x: e.clientX + b.scrollLeft + de.scrollLeft, - y: e.clientY + b.scrollTop + de.scrollTop - }; - } - } -}; -})(); - -/** - * Text Utilities - */ -(function () { - -var - F = Flotr, - D = F.DOM, - _ = F._, - -Text = function (o) { - this.o = o; -}; - -Text.prototype = { - - dimensions : function (text, canvasStyle, htmlStyle, className) { - - if (!text) return { width : 0, height : 0 }; - - return (this.o.html) ? - this.html(text, this.o.element, htmlStyle, className) : - this.canvas(text, canvasStyle); - }, - - canvas : function (text, style) { - - if (!this.o.textEnabled) return; - style = style || {}; - - var - metrics = this.measureText(text, style), - width = metrics.width, - height = style.size || F.defaultOptions.fontSize, - angle = style.angle || 0, - cosAngle = Math.cos(angle), - sinAngle = Math.sin(angle), - widthPadding = 2, - heightPadding = 6, - bounds; - - bounds = { - width: Math.abs(cosAngle * width) + Math.abs(sinAngle * height) + widthPadding, - height: Math.abs(sinAngle * width) + Math.abs(cosAngle * height) + heightPadding - }; - - return bounds; - }, - - html : function (text, element, style, className) { - - var div = D.create('div'); - - D.setStyles(div, { 'position' : 'absolute', 'top' : '-10000px' }); - D.insert(div, '
    ' + text + '
    '); - D.insert(this.o.element, div); - - return D.size(div); - }, - - measureText : function (text, style) { - - var - context = this.o.ctx, - metrics; - - if (!context.fillText || (F.isIphone && context.measure)) { - return { width : context.measure(text, style)}; - } - - style = _.extend({ - size: F.defaultOptions.fontSize, - weight: 1, - angle: 0 - }, style); - - context.save(); - context.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif"; - metrics = context.measureText(text); - context.restore(); - - return metrics; - } -}; - -Flotr.Text = Text; - -})(); - -/** - * Flotr Graph class that plots a graph on creation. - */ -(function () { - -var - D = Flotr.DOM, - E = Flotr.EventAdapter, - _ = Flotr._, - flotr = Flotr; -/** - * Flotr Graph constructor. - * @param {Element} el - element to insert the graph into - * @param {Object} data - an array or object of dataseries - * @param {Object} options - an object containing options - */ -Graph = function(el, data, options){ -// Let's see if we can get away with out this [JS] -// try { - this._setEl(el); - this._initMembers(); - this._initPlugins(); - - E.fire(this.el, 'flotr:beforeinit', [this]); - - this.data = data; - this.series = flotr.Series.getSeries(data); - this._initOptions(options); - this._initGraphTypes(); - this._initCanvas(); - this._text = new flotr.Text({ - element : this.el, - ctx : this.ctx, - html : this.options.HtmlText, - textEnabled : this.textEnabled - }); - E.fire(this.el, 'flotr:afterconstruct', [this]); - this._initEvents(); - - this.findDataRanges(); - this.calculateSpacing(); - - this.draw(_.bind(function() { - E.fire(this.el, 'flotr:afterinit', [this]); - }, this)); -/* - try { - } catch (e) { - try { - console.error(e); - } catch (e2) {} - }*/ -}; - -function observe (object, name, callback) { - E.observe.apply(this, arguments); - this._handles.push(arguments); - return this; -} - -Graph.prototype = { - - destroy: function () { - E.fire(this.el, 'flotr:destroy'); - _.each(this._handles, function (handle) { - E.stopObserving.apply(this, handle); - }); - this._handles = []; - this.el.graph = null; - }, - - observe : observe, - - /** - * @deprecated - */ - _observe : observe, - - processColor: function(color, options){ - var o = { x1: 0, y1: 0, x2: this.plotWidth, y2: this.plotHeight, opacity: 1, ctx: this.ctx }; - _.extend(o, options); - return flotr.Color.processColor(color, o); - }, - /** - * Function determines the min and max values for the xaxis and yaxis. - * - * TODO logarithmic range validation (consideration of 0) - */ - findDataRanges: function(){ - var a = this.axes, - xaxis, yaxis, range; - - _.each(this.series, function (series) { - range = series.getRange(); - if (range) { - xaxis = series.xaxis; - yaxis = series.yaxis; - xaxis.datamin = Math.min(range.xmin, xaxis.datamin); - xaxis.datamax = Math.max(range.xmax, xaxis.datamax); - yaxis.datamin = Math.min(range.ymin, yaxis.datamin); - yaxis.datamax = Math.max(range.ymax, yaxis.datamax); - xaxis.used = (xaxis.used || range.xused); - yaxis.used = (yaxis.used || range.yused); - } - }, this); - - // Check for empty data, no data case (none used) - if (!a.x.used && !a.x2.used) a.x.used = true; - if (!a.y.used && !a.y2.used) a.y.used = true; - - _.each(a, function (axis) { - axis.calculateRange(); - }); - - var - types = _.keys(flotr.graphTypes), - drawn = false; - - _.each(this.series, function (series) { - if (series.hide) return; - _.each(types, function (type) { - if (series[type] && series[type].show) { - this.extendRange(type, series); - drawn = true; - } - }, this); - if (!drawn) { - this.extendRange(this.options.defaultType, series); - } - }, this); - }, - - extendRange : function (type, series) { - if (this[type].extendRange) this[type].extendRange(series, series.data, series[type], this[type]); - if (this[type].extendYRange) this[type].extendYRange(series.yaxis, series.data, series[type], this[type]); - if (this[type].extendXRange) this[type].extendXRange(series.xaxis, series.data, series[type], this[type]); - }, - - /** - * Calculates axis label sizes. - */ - calculateSpacing: function(){ - - var a = this.axes, - options = this.options, - series = this.series, - margin = options.grid.labelMargin, - T = this._text, - x = a.x, - x2 = a.x2, - y = a.y, - y2 = a.y2, - maxOutset = options.grid.outlineWidth, - i, j, l, dim; - - // TODO post refactor, fix this - _.each(a, function (axis) { - axis.calculateTicks(); - axis.calculateTextDimensions(T, options); - }); - - // Title height - dim = T.dimensions( - options.title, - {size: options.fontSize*1.5}, - 'font-size:1em;font-weight:bold;', - 'flotr-title' - ); - this.titleHeight = dim.height; - - // Subtitle height - dim = T.dimensions( - options.subtitle, - {size: options.fontSize}, - 'font-size:smaller;', - 'flotr-subtitle' - ); - this.subtitleHeight = dim.height; - - for(j = 0; j < options.length; ++j){ - if (series[j].points.show){ - maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2); - } - } - - var p = this.plotOffset; - if (x.options.margin === false) { - p.bottom = 0; - p.top = 0; - } else { - p.bottom += (options.grid.circular ? 0 : (x.used && x.options.showLabels ? (x.maxLabel.height + margin) : 0)) + - (x.used && x.options.title ? (x.titleSize.height + margin) : 0) + maxOutset; - - p.top += (options.grid.circular ? 0 : (x2.used && x2.options.showLabels ? (x2.maxLabel.height + margin) : 0)) + - (x2.used && x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight + maxOutset; - } - if (y.options.margin === false) { - p.left = 0; - p.right = 0; - } else { - p.left += (options.grid.circular ? 0 : (y.used && y.options.showLabels ? (y.maxLabel.width + margin) : 0)) + - (y.used && y.options.title ? (y.titleSize.width + margin) : 0) + maxOutset; - - p.right += (options.grid.circular ? 0 : (y2.used && y2.options.showLabels ? (y2.maxLabel.width + margin) : 0)) + - (y2.used && y2.options.title ? (y2.titleSize.width + margin) : 0) + maxOutset; - } - - p.top = Math.floor(p.top); // In order the outline not to be blured - - this.plotWidth = this.canvasWidth - p.left - p.right; - this.plotHeight = this.canvasHeight - p.bottom - p.top; - - // TODO post refactor, fix this - x.length = x2.length = this.plotWidth; - y.length = y2.length = this.plotHeight; - y.offset = y2.offset = this.plotHeight; - x.setScale(); - x2.setScale(); - y.setScale(); - y2.setScale(); - }, - /** - * Draws grid, labels, series and outline. - */ - draw: function(after) { - - var - context = this.ctx, - i; - - E.fire(this.el, 'flotr:beforedraw', [this.series, this]); - - if (this.series.length) { - - context.save(); - context.translate(this.plotOffset.left, this.plotOffset.top); - - for (i = 0; i < this.series.length; i++) { - if (!this.series[i].hide) this.drawSeries(this.series[i]); - } - - context.restore(); - this.clip(); - } - - E.fire(this.el, 'flotr:afterdraw', [this.series, this]); - if (after) after(); - }, - /** - * Actually draws the graph. - * @param {Object} series - series to draw - */ - drawSeries: function(series){ - - function drawChart (series, typeKey) { - var options = this.getOptions(series, typeKey); - this[typeKey].draw(options); - } - - var drawn = false; - series = series || this.series; - - _.each(flotr.graphTypes, function (type, typeKey) { - if (series[typeKey] && series[typeKey].show && this[typeKey]) { - drawn = true; - drawChart.call(this, series, typeKey); - } - }, this); - - if (!drawn) drawChart.call(this, series, this.options.defaultType); - }, - - getOptions : function (series, typeKey) { - var - type = series[typeKey], - graphType = this[typeKey], - options = { - context : this.ctx, - width : this.plotWidth, - height : this.plotHeight, - fontSize : this.options.fontSize, - fontColor : this.options.fontColor, - textEnabled : this.textEnabled, - htmlText : this.options.HtmlText, - text : this._text, // TODO Is this necessary? - element : this.el, - data : series.data, - color : series.color, - shadowSize : series.shadowSize, - xScale : _.bind(series.xaxis.d2p, series.xaxis), - yScale : _.bind(series.yaxis.d2p, series.yaxis) - }; - - options = flotr.merge(type, options); - - // Fill - options.fillStyle = this.processColor( - type.fillColor || series.color, - {opacity: type.fillOpacity} - ); - - return options; - }, - /** - * Calculates the coordinates from a mouse event object. - * @param {Event} event - Mouse Event object. - * @return {Object} Object with coordinates of the mouse. - */ - getEventPosition: function (e){ - - var - d = document, - b = d.body, - de = d.documentElement, - axes = this.axes, - plotOffset = this.plotOffset, - lastMousePos = this.lastMousePos, - pointer = E.eventPointer(e), - dx = pointer.x - lastMousePos.pageX, - dy = pointer.y - lastMousePos.pageY, - r, rx, ry; - - if ('ontouchstart' in this.el) { - r = D.position(this.overlay); - rx = pointer.x - r.left - plotOffset.left; - ry = pointer.y - r.top - plotOffset.top; - } else { - r = this.overlay.getBoundingClientRect(); - rx = e.clientX - r.left - plotOffset.left - b.scrollLeft - de.scrollLeft; - ry = e.clientY - r.top - plotOffset.top - b.scrollTop - de.scrollTop; - } - - return { - x: axes.x.p2d(rx), - x2: axes.x2.p2d(rx), - y: axes.y.p2d(ry), - y2: axes.y2.p2d(ry), - relX: rx, - relY: ry, - dX: dx, - dY: dy, - absX: pointer.x, - absY: pointer.y, - pageX: pointer.x, - pageY: pointer.y - }; - }, - /** - * Observes the 'click' event and fires the 'flotr:click' event. - * @param {Event} event - 'click' Event object. - */ - clickHandler: function(event){ - if(this.ignoreClick){ - this.ignoreClick = false; - return this.ignoreClick; - } - E.fire(this.el, 'flotr:click', [this.getEventPosition(event), this]); - }, - /** - * Observes mouse movement over the graph area. Fires the 'flotr:mousemove' event. - * @param {Event} event - 'mousemove' Event object. - */ - mouseMoveHandler: function(event){ - if (this.mouseDownMoveHandler) return; - var pos = this.getEventPosition(event); - E.fire(this.el, 'flotr:mousemove', [event, pos, this]); - this.lastMousePos = pos; - }, - /** - * Observes the 'mousedown' event. - * @param {Event} event - 'mousedown' Event object. - */ - mouseDownHandler: function (event){ - - /* - // @TODO Context menu? - if(event.isRightClick()) { - event.stop(); - - var overlay = this.overlay; - overlay.hide(); - - function cancelContextMenu () { - overlay.show(); - E.stopObserving(document, 'mousemove', cancelContextMenu); - } - E.observe(document, 'mousemove', cancelContextMenu); - return; - } - */ - - if (this.mouseUpHandler) return; - this.mouseUpHandler = _.bind(function (e) { - E.stopObserving(document, 'mouseup', this.mouseUpHandler); - E.stopObserving(document, 'mousemove', this.mouseDownMoveHandler); - this.mouseDownMoveHandler = null; - this.mouseUpHandler = null; - // @TODO why? - //e.stop(); - E.fire(this.el, 'flotr:mouseup', [e, this]); - }, this); - this.mouseDownMoveHandler = _.bind(function (e) { - var pos = this.getEventPosition(e); - E.fire(this.el, 'flotr:mousemove', [event, pos, this]); - this.lastMousePos = pos; - }, this); - E.observe(document, 'mouseup', this.mouseUpHandler); - E.observe(document, 'mousemove', this.mouseDownMoveHandler); - E.fire(this.el, 'flotr:mousedown', [event, this]); - this.ignoreClick = false; - }, - drawTooltip: function(content, x, y, options) { - var mt = this.getMouseTrack(), - 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;', - p = options.position, - m = options.margin, - plotOffset = this.plotOffset; - - if(x !== null && y !== null){ - if (!options.relative) { // absolute to the canvas - if(p.charAt(0) == 'n') style += 'top:' + (m + plotOffset.top) + 'px;bottom:auto;'; - else if(p.charAt(0) == 's') style += 'bottom:' + (m + plotOffset.bottom) + 'px;top:auto;'; - if(p.charAt(1) == 'e') style += 'right:' + (m + plotOffset.right) + 'px;left:auto;'; - else if(p.charAt(1) == 'w') style += 'left:' + (m + plotOffset.left) + 'px;right:auto;'; - } - else { // relative to the mouse - if(p.charAt(0) == 'n') style += 'bottom:' + (m - plotOffset.top - y + this.canvasHeight) + 'px;top:auto;'; - else if(p.charAt(0) == 's') style += 'top:' + (m + plotOffset.top + y) + 'px;bottom:auto;'; - if(p.charAt(1) == 'e') style += 'left:' + (m + plotOffset.left + x) + 'px;right:auto;'; - else if(p.charAt(1) == 'w') style += 'right:' + (m - plotOffset.left - x + this.canvasWidth) + 'px;left:auto;'; - } - - mt.style.cssText = style; - D.empty(mt); - D.insert(mt, content); - D.show(mt); - } - else { - D.hide(mt); - } - }, - - clip: function () { - - var - ctx = this.ctx, - o = this.plotOffset, - w = this.canvasWidth, - h = this.canvasHeight; - - if (flotr.isIE && flotr.isIE < 9) { - // Clipping for excanvas :-( - ctx.save(); - ctx.fillStyle = this.processColor(this.options.ieBackgroundColor); - ctx.fillRect(0, 0, w, o.top); - ctx.fillRect(0, 0, o.left, h); - ctx.fillRect(0, h - o.bottom, w, o.bottom); - ctx.fillRect(w - o.right, 0, o.right,h); - ctx.restore(); - } else { - ctx.clearRect(0, 0, w, o.top); - ctx.clearRect(0, 0, o.left, h); - ctx.clearRect(0, h - o.bottom, w, o.bottom); - ctx.clearRect(w - o.right, 0, o.right,h); - } - }, - - _initMembers: function() { - this._handles = []; - this.lastMousePos = {pageX: null, pageY: null }; - this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0}; - this.ignoreClick = true; - this.prevHit = null; - }, - - _initGraphTypes: function() { - _.each(flotr.graphTypes, function(handler, graphType){ - this[graphType] = flotr.clone(handler); - }, this); - }, - - _initEvents: function () { - - var - el = this.el, - touchendHandler, movement, touchend; - - if ('ontouchstart' in el) { - - touchendHandler = _.bind(function (e) { - touchend = true; - E.stopObserving(document, 'touchend', touchendHandler); - E.fire(el, 'flotr:mouseup', [event, this]); - this.multitouches = null; - - if (!movement) { - this.clickHandler(e); - } - }, this); - - this.observe(this.overlay, 'touchstart', _.bind(function (e) { - movement = false; - touchend = false; - this.ignoreClick = false; - - if (e.touches && e.touches.length > 1) { - this.multitouches = e.touches; - } - - E.fire(el, 'flotr:mousedown', [event, this]); - this.observe(document, 'touchend', touchendHandler); - }, this)); - - this.observe(this.overlay, 'touchmove', _.bind(function (e) { - - var pos = this.getEventPosition(e); - - e.preventDefault(); - - movement = true; - - if (this.multitouches || (e.touches && e.touches.length > 1)) { - this.multitouches = e.touches; - } else { - if (!touchend) { - E.fire(el, 'flotr:mousemove', [event, pos, this]); - } - } - this.lastMousePos = pos; - }, this)); - - } else { - this. - observe(this.overlay, 'mousedown', _.bind(this.mouseDownHandler, this)). - observe(el, 'mousemove', _.bind(this.mouseMoveHandler, this)). - observe(this.overlay, 'click', _.bind(this.clickHandler, this)). - observe(el, 'mouseout', function () { - E.fire(el, 'flotr:mouseout'); - }); - } - }, - - /** - * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use - * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements - * are created, the elements are inserted into the container element. - */ - _initCanvas: function(){ - var el = this.el, - o = this.options, - children = el.children, - removedChildren = [], - child, i, - size, style; - - // Empty the el - for (i = children.length; i--;) { - child = children[i]; - if (!this.canvas && child.className === 'flotr-canvas') { - this.canvas = child; - } else if (!this.overlay && child.className === 'flotr-overlay') { - this.overlay = child; - } else { - removedChildren.push(child); - } - } - for (i = removedChildren.length; i--;) { - el.removeChild(removedChildren[i]); - } - - D.setStyles(el, {position: 'relative'}); // For positioning labels and overlay. - size = {}; - size.width = el.clientWidth; - size.height = el.clientHeight; - - if(size.width <= 0 || size.height <= 0 || o.resolution <= 0){ - throw 'Invalid dimensions for plot, width = ' + size.width + ', height = ' + size.height + ', resolution = ' + o.resolution; - } - - // Main canvas for drawing graph types - this.canvas = getCanvas(this.canvas, 'canvas'); - // Overlay canvas for interactive features - this.overlay = getCanvas(this.overlay, 'overlay'); - this.ctx = getContext(this.canvas); - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); - this.octx = getContext(this.overlay); - this.octx.clearRect(0, 0, this.overlay.width, this.overlay.height); - this.canvasHeight = size.height; - this.canvasWidth = size.width; - this.textEnabled = !!this.ctx.drawText || !!this.ctx.fillText; // Enable text functions - - function getCanvas(canvas, name){ - if(!canvas){ - canvas = D.create('canvas'); - if (typeof FlashCanvas != "undefined" && typeof canvas.getContext === 'function') { - FlashCanvas.initElement(canvas); - } - canvas.className = 'flotr-'+name; - canvas.style.cssText = 'position:absolute;left:0px;top:0px;'; - D.insert(el, canvas); - } - _.each(size, function(size, attribute){ - D.show(canvas); - if (name == 'canvas' && canvas.getAttribute(attribute) === size) { - return; - } - canvas.setAttribute(attribute, size * o.resolution); - canvas.style[attribute] = size + 'px'; - }); - canvas.context_ = null; // Reset the ExCanvas context - return canvas; - } - - function getContext(canvas){ - if(window.G_vmlCanvasManager) window.G_vmlCanvasManager.initElement(canvas); // For ExCanvas - var context = canvas.getContext('2d'); - if(!window.G_vmlCanvasManager) context.scale(o.resolution, o.resolution); - return context; - } - }, - - _initPlugins: function(){ - // TODO Should be moved to flotr and mixed in. - _.each(flotr.plugins, function(plugin, name){ - _.each(plugin.callbacks, function(fn, c){ - this.observe(this.el, c, _.bind(fn, this)); - }, this); - this[name] = flotr.clone(plugin); - _.each(this[name], function(fn, p){ - if (_.isFunction(fn)) - this[name][p] = _.bind(fn, this); - }, this); - }, this); - }, - - /** - * Sets options and initializes some variables and color specific values, used by the constructor. - * @param {Object} opts - options object - */ - _initOptions: function(opts){ - var options = flotr.clone(flotr.defaultOptions); - options.x2axis = _.extend(_.clone(options.xaxis), options.x2axis); - options.y2axis = _.extend(_.clone(options.yaxis), options.y2axis); - this.options = flotr.merge(opts || {}, options); - - if (this.options.grid.minorVerticalLines === null && - this.options.xaxis.scaling === 'logarithmic') { - this.options.grid.minorVerticalLines = true; - } - if (this.options.grid.minorHorizontalLines === null && - this.options.yaxis.scaling === 'logarithmic') { - this.options.grid.minorHorizontalLines = true; - } - - E.fire(this.el, 'flotr:afterinitoptions', [this]); - - this.axes = flotr.Axis.getAxes(this.options); - - // Initialize some variables used throughout this function. - var assignedColors = [], - colors = [], - ln = this.series.length, - neededColors = this.series.length, - oc = this.options.colors, - usedColors = [], - variation = 0, - c, i, j, s; - - // Collect user-defined colors from series. - for(i = neededColors - 1; i > -1; --i){ - c = this.series[i].color; - if(c){ - --neededColors; - if(_.isNumber(c)) assignedColors.push(c); - else usedColors.push(flotr.Color.parse(c)); - } - } - - // Calculate the number of colors that need to be generated. - for(i = assignedColors.length - 1; i > -1; --i) - neededColors = Math.max(neededColors, assignedColors[i] + 1); - - // Generate needed number of colors. - for(i = 0; colors.length < neededColors;){ - c = (oc.length == i) ? new flotr.Color(100, 100, 100) : flotr.Color.parse(oc[i]); - - // Make sure each serie gets a different color. - var sign = variation % 2 == 1 ? -1 : 1, - factor = 1 + sign * Math.ceil(variation / 2) * 0.2; - c.scale(factor, factor, factor); - - /** - * @todo if we're getting too close to something else, we should probably skip this one - */ - colors.push(c); - - if(++i >= oc.length){ - i = 0; - ++variation; - } - } - - // Fill the options with the generated colors. - for(i = 0, j = 0; i < ln; ++i){ - s = this.series[i]; - - // Assign the color. - if (!s.color){ - s.color = colors[j++].toString(); - }else if(_.isNumber(s.color)){ - s.color = colors[s.color].toString(); - } - - // Every series needs an axis - if (!s.xaxis) s.xaxis = this.axes.x; - if (s.xaxis == 1) s.xaxis = this.axes.x; - else if (s.xaxis == 2) s.xaxis = this.axes.x2; - - if (!s.yaxis) s.yaxis = this.axes.y; - if (s.yaxis == 1) s.yaxis = this.axes.y; - else if (s.yaxis == 2) s.yaxis = this.axes.y2; - - // Apply missing options to the series. - for (var t in flotr.graphTypes){ - s[t] = _.extend(_.clone(this.options[t]), s[t]); - } - s.mouse = _.extend(_.clone(this.options.mouse), s.mouse); - - if (_.isUndefined(s.shadowSize)) s.shadowSize = this.options.shadowSize; - } - }, - - _setEl: function(el) { - if (!el) throw 'The target container doesn\'t exist'; - else if (el.graph instanceof Graph) el.graph.destroy(); - else if (!el.clientWidth) throw 'The target container must be visible'; - - el.graph = this; - this.el = el; - } -}; - -Flotr.Graph = Graph; - -})(); - -/** - * Flotr Axis Library - */ - -(function () { - -var - _ = Flotr._, - LOGARITHMIC = 'logarithmic'; - -function Axis (o) { - - this.orientation = 1; - this.offset = 0; - this.datamin = Number.MAX_VALUE; - this.datamax = -Number.MAX_VALUE; - - _.extend(this, o); - - this._setTranslations(); -} - - -// Prototype -Axis.prototype = { - - setScale : function () { - var length = this.length; - if (this.options.scaling == LOGARITHMIC) { - this.scale = length / (log(this.max, this.options.base) - log(this.min, this.options.base)); - } else { - this.scale = length / (this.max - this.min); - } - }, - - calculateTicks : function () { - var options = this.options; - - this.ticks = []; - this.minorTicks = []; - - // User Ticks - if(options.ticks){ - this._cleanUserTicks(options.ticks, this.ticks); - this._cleanUserTicks(options.minorTicks || [], this.minorTicks); - } - else { - if (options.mode == 'time') { - this._calculateTimeTicks(); - } else if (options.scaling === 'logarithmic') { - this._calculateLogTicks(); - } else { - this._calculateTicks(); - } - } - }, - - /** - * Calculates the range of an axis to apply autoscaling. - */ - calculateRange: function () { - - if (!this.used) return; - - var axis = this, - o = axis.options, - min = o.min !== null ? o.min : axis.datamin, - max = o.max !== null ? o.max : axis.datamax, - margin = o.autoscaleMargin; - - if (o.scaling == 'logarithmic') { - if (min <= 0) min = axis.datamin; - - // Let it widen later on - if (max <= 0) max = min; - } - - if (max == min) { - var widen = max ? 0.01 : 1.00; - if (o.min === null) min -= widen; - if (o.max === null) max += widen; - } - - if (o.scaling === 'logarithmic') { - if (min < 0) min = max / o.base; // Could be the result of widening - - var maxexp = Math.log(max); - if (o.base != Math.E) maxexp /= Math.log(o.base); - maxexp = Math.ceil(maxexp); - - var minexp = Math.log(min); - if (o.base != Math.E) minexp /= Math.log(o.base); - minexp = Math.ceil(minexp); - - axis.tickSize = Flotr.getTickSize(o.noTicks, minexp, maxexp, o.tickDecimals === null ? 0 : o.tickDecimals); - - // Try to determine a suitable amount of miniticks based on the length of a decade - if (o.minorTickFreq === null) { - if (maxexp - minexp > 10) - o.minorTickFreq = 0; - else if (maxexp - minexp > 5) - o.minorTickFreq = 2; - else - o.minorTickFreq = 5; - } - } else { - axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals); - } - - axis.min = min; - axis.max = max; //extendRange may use axis.min or axis.max, so it should be set before it is caled - - // Autoscaling. @todo This probably fails with log scale. Find a testcase and fix it - if(o.min === null && o.autoscale){ - axis.min -= axis.tickSize * margin; - // Make sure we don't go below zero if all values are positive. - if(axis.min < 0 && axis.datamin >= 0) axis.min = 0; - axis.min = axis.tickSize * Math.floor(axis.min / axis.tickSize); - } - - if(o.max === null && o.autoscale){ - axis.max += axis.tickSize * margin; - if(axis.max > 0 && axis.datamax <= 0 && axis.datamax != axis.datamin) axis.max = 0; - axis.max = axis.tickSize * Math.ceil(axis.max / axis.tickSize); - } - - if (axis.min == axis.max) axis.max = axis.min + 1; - }, - - calculateTextDimensions : function (T, options) { - - var maxLabel = '', - length, - i; - - if (this.options.showLabels) { - for (i = 0; i < this.ticks.length; ++i) { - length = this.ticks[i].label.length; - if (length > maxLabel.length){ - maxLabel = this.ticks[i].label; - } - } - } - - this.maxLabel = T.dimensions( - maxLabel, - {size:options.fontSize, angle: Flotr.toRad(this.options.labelsAngle)}, - 'font-size:smaller;', - 'flotr-grid-label' - ); - - this.titleSize = T.dimensions( - this.options.title, - {size:options.fontSize*1.2, angle: Flotr.toRad(this.options.titleAngle)}, - 'font-weight:bold;', - 'flotr-axis-title' - ); - }, - - _cleanUserTicks : function (ticks, axisTicks) { - - var axis = this, options = this.options, - v, i, label, tick; - - if(_.isFunction(ticks)) ticks = ticks({min : axis.min, max : axis.max}); - - for(i = 0; i < ticks.length; ++i){ - tick = ticks[i]; - if(typeof(tick) === 'object'){ - v = tick[0]; - label = (tick.length > 1) ? tick[1] : options.tickFormatter(v, {min : axis.min, max : axis.max}); - } else { - v = tick; - label = options.tickFormatter(v, {min : this.min, max : this.max}); - } - axisTicks[i] = { v: v, label: label }; - } - }, - - _calculateTimeTicks : function () { - this.ticks = Flotr.Date.generator(this); - }, - - _calculateLogTicks : function () { - - var axis = this, - o = axis.options, - v, - decadeStart; - - var max = Math.log(axis.max); - if (o.base != Math.E) max /= Math.log(o.base); - max = Math.ceil(max); - - var min = Math.log(axis.min); - if (o.base != Math.E) min /= Math.log(o.base); - min = Math.ceil(min); - - for (i = min; i < max; i += axis.tickSize) { - decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i); - // Next decade begins here: - var decadeEnd = decadeStart * ((o.base == Math.E) ? Math.exp(axis.tickSize) : Math.pow(o.base, axis.tickSize)); - var stepSize = (decadeEnd - decadeStart) / o.minorTickFreq; - - axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})}); - for (v = decadeStart + stepSize; v < decadeEnd; v += stepSize) - axis.minorTicks.push({v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max})}); - } - - // Always show the value at the would-be start of next decade (end of this decade) - decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i); - axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})}); - }, - - _calculateTicks : function () { - - var axis = this, - o = axis.options, - tickSize = axis.tickSize, - min = axis.min, - max = axis.max, - start = tickSize * Math.ceil(min / tickSize), // Round to nearest multiple of tick size. - decimals, - minorTickSize, - v, v2, - i, j; - - if (o.minorTickFreq) - minorTickSize = tickSize / o.minorTickFreq; - - // Then store all possible ticks. - for (i = 0; (v = v2 = start + i * tickSize) <= max; ++i){ - - // Round (this is always needed to fix numerical instability). - decimals = o.tickDecimals; - if (decimals === null) decimals = 1 - Math.floor(Math.log(tickSize) / Math.LN10); - if (decimals < 0) decimals = 0; - - v = v.toFixed(decimals); - axis.ticks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) }); - - if (o.minorTickFreq) { - for (j = 0; j < o.minorTickFreq && (i * tickSize + j * minorTickSize) < max; ++j) { - v = v2 + j * minorTickSize; - axis.minorTicks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) }); - } - } - } - - }, - - _setTranslations : function (logarithmic) { - this.d2p = (logarithmic ? d2pLog : d2p); - this.p2d = (logarithmic ? p2dLog : p2d); - } -}; - - -// Static Methods -_.extend(Axis, { - getAxes : function (options) { - return { - x: new Axis({options: options.xaxis, n: 1, length: this.plotWidth}), - x2: new Axis({options: options.x2axis, n: 2, length: this.plotWidth}), - y: new Axis({options: options.yaxis, n: 1, length: this.plotHeight, offset: this.plotHeight, orientation: -1}), - y2: new Axis({options: options.y2axis, n: 2, length: this.plotHeight, offset: this.plotHeight, orientation: -1}) - }; - } -}); - - -// Helper Methods - -function d2p (dataValue) { - return this.offset + this.orientation * (dataValue - this.min) * this.scale; -} - -function p2d (pointValue) { - return (this.offset + this.orientation * pointValue) / this.scale + this.min; -} - -function d2pLog (dataValue) { - return this.offset + this.orientation * (log(dataValue, this.options.base) - log(this.min, this.options.base)) * this.scale; -} - -function p2dLog (pointValue) { - return exp((this.offset + this.orientation * pointValue) / this.scale + log(this.min, this.options.base), this.options.base); -} - -function log (value, base) { - value = Math.log(Math.max(value, Number.MIN_VALUE)); - if (base !== Math.E) - value /= Math.log(base); - return value; -} - -function exp (value, base) { - return (base === Math.E) ? Math.exp(value) : Math.pow(base, value); -} - -Flotr.Axis = Axis; - -})(); - -/** - * Flotr Series Library - */ - -(function () { - -var - _ = Flotr._; - -function Series (o) { - _.extend(this, o); -} - -Series.prototype = { - - getRange: function () { - - var - data = this.data, - length = data.length, - xmin = Number.MAX_VALUE, - ymin = Number.MAX_VALUE, - xmax = -Number.MAX_VALUE, - ymax = -Number.MAX_VALUE, - xused = false, - yused = false, - x, y, i; - - if (length < 0 || this.hide) return false; - - for (i = 0; i < length; i++) { - x = data[i][0]; - y = data[i][1]; - if (x < xmin) { xmin = x; xused = true; } - if (x > xmax) { xmax = x; xused = true; } - if (y < ymin) { ymin = y; yused = true; } - if (y > ymax) { ymax = y; yused = true; } - } - - return { - xmin : xmin, - xmax : xmax, - ymin : ymin, - ymax : ymax, - xused : xused, - yused : yused - }; - } -}; - -_.extend(Series, { - /** - * Collects dataseries from input and parses the series into the right format. It returns an Array - * of Objects each having at least the 'data' key set. - * @param {Array, Object} data - Object or array of dataseries - * @return {Array} Array of Objects parsed into the right format ({(...,) data: [[x1,y1], [x2,y2], ...] (, ...)}) - */ - getSeries: function(data){ - return _.map(data, function(s){ - var series; - if (s.data) { - series = new Series(); - _.extend(series, s); - } else { - series = new Series({data:s}); - } - return series; - }); - } -}); - -Flotr.Series = Series; - -})(); - -/** Lines **/ -Flotr.addType('lines', { - options: { - show: false, // => setting to true will show lines, false will hide - lineWidth: 2, // => line width in pixels - fill: false, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillBorder: false, // => draw a border around the fill - fillColor: null, // => fill color - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - steps: false, // => draw steps - stacked: false // => setting to true will show stacked lines, false will show normal lines - }, - - stack : { - values : [] - }, - - /** - * Draws lines series in the canvas element. - * @param {Object} options - */ - draw : function (options) { - - var - context = options.context, - lineWidth = options.lineWidth, - shadowSize = options.shadowSize, - offset; - - context.save(); - context.lineJoin = 'round'; - - if (shadowSize) { - - context.lineWidth = shadowSize / 2; - offset = lineWidth / 2 + context.lineWidth / 2; - - // @TODO do this instead with a linear gradient - context.strokeStyle = "rgba(0,0,0,0.1)"; - this.plot(options, offset + shadowSize / 2, false); - - context.strokeStyle = "rgba(0,0,0,0.2)"; - this.plot(options, offset, false); - } - - context.lineWidth = lineWidth; - context.strokeStyle = options.color; - - this.plot(options, 0, true); - - context.restore(); - }, - - plot : function (options, shadowOffset, incStack) { - - var - context = options.context, - width = options.width, - height = options.height, - xScale = options.xScale, - yScale = options.yScale, - data = options.data, - stack = options.stacked ? this.stack : false, - length = data.length - 1, - prevx = null, - prevy = null, - zero = yScale(0), - x1, x2, y1, y2, stack1, stack2, i; - - if (length < 1) return; - - context.beginPath(); - - for (i = 0; i < length; ++i) { - - // To allow empty values - if (data[i][1] === null || data[i+1][1] === null) continue; - - // Zero is infinity for log scales - // TODO handle zero for logarithmic - // if (xa.options.scaling === 'logarithmic' && (data[i][0] <= 0 || data[i+1][0] <= 0)) continue; - // if (ya.options.scaling === 'logarithmic' && (data[i][1] <= 0 || data[i+1][1] <= 0)) continue; - - x1 = xScale(data[i][0]); - x2 = xScale(data[i+1][0]); - - if (stack) { - - stack1 = stack.values[data[i][0]] || 0; - stack2 = stack.values[data[i+1][0]] || stack.values[data[i][0]] || 0; - - y1 = yScale(data[i][1] + stack1); - y2 = yScale(data[i+1][1] + stack2); - - if(incStack){ - stack.values[data[i][0]] = data[i][1]+stack1; - - if(i == length-1) - stack.values[data[i+1][0]] = data[i+1][1]+stack2; - } - } - else{ - y1 = yScale(data[i][1]); - y2 = yScale(data[i+1][1]); - } - - if ( - (y1 > height && y2 > height) || - (y1 < 0 && y2 < 0) || - (x1 < 0 && x2 < 0) || - (x1 > width && x2 > width) - ) continue; - - if((prevx != x1) || (prevy != y1 + shadowOffset)) - context.moveTo(x1, y1 + shadowOffset); - - prevx = x2; - prevy = y2 + shadowOffset; - if (options.steps) { - context.lineTo(prevx + shadowOffset / 2, y1 + shadowOffset); - context.lineTo(prevx + shadowOffset / 2, prevy); - } else { - context.lineTo(prevx, prevy); - } - } - - if (!options.fill || options.fill && !options.fillBorder) context.stroke(); - - // TODO stacked lines - if(!shadowOffset && options.fill){ - x1 = xScale(data[0][0]); - context.fillStyle = options.fillStyle; - context.lineTo(x2, zero); - context.lineTo(x1, zero); - context.lineTo(x1, yScale(data[0][1])); - context.fill(); - if (options.fillBorder) { - context.stroke(); - } - } - - context.closePath(); - }, - - // Perform any pre-render precalculations (this should be run on data first) - // - Pie chart total for calculating measures - // - Stacks for lines and bars - // precalculate : function () { - // } - // - // - // Get any bounds after pre calculation (axis can fetch this if does not have explicit min/max) - // getBounds : function () { - // } - // getMin : function () { - // } - // getMax : function () { - // } - // - // - // Padding around rendered elements - // getPadding : function () { - // } - - extendYRange : function (axis, data, options, lines) { - - var o = axis.options; - - // If stacked and auto-min - if (options.stacked && ((!o.max && o.max !== 0) || (!o.min && o.min !== 0))) { - - var - newmax = axis.max, - newmin = axis.min, - positiveSums = lines.positiveSums || {}, - negativeSums = lines.negativeSums || {}, - x, j; - - for (j = 0; j < data.length; j++) { - - x = data[j][0] + ''; - - // Positive - if (data[j][1] > 0) { - positiveSums[x] = (positiveSums[x] || 0) + data[j][1]; - newmax = Math.max(newmax, positiveSums[x]); - } - - // Negative - else { - negativeSums[x] = (negativeSums[x] || 0) + data[j][1]; - newmin = Math.min(newmin, negativeSums[x]); - } - } - - lines.negativeSums = negativeSums; - lines.positiveSums = positiveSums; - - axis.max = newmax; - axis.min = newmin; - } - - if (options.steps) { - - this.hit = function (options) { - var - data = options.data, - args = options.args, - yScale = options.yScale, - mouse = args[0], - length = data.length, - n = args[1], - x = mouse.x, - relY = mouse.relY, - i; - - for (i = 0; i < length - 1; i++) { - if (x >= data[i][0] && x <= data[i+1][0]) { - if (Math.abs(yScale(data[i][1]) - relY) < 8) { - n.x = data[i][0]; - n.y = data[i][1]; - n.index = i; - n.seriesIndex = options.index; - } - break; - } - } - }; - - this.drawHit = function (options) { - var - context = options.context, - args = options.args, - data = options.data, - xScale = options.xScale, - index = args.index, - x = xScale(args.x), - y = options.yScale(args.y), - x2; - - if (data.length - 1 > index) { - x2 = options.xScale(data[index + 1][0]); - context.save(); - context.strokeStyle = options.color; - context.lineWidth = options.lineWidth; - context.beginPath(); - context.moveTo(x, y); - context.lineTo(x2, y); - context.stroke(); - context.closePath(); - context.restore(); - } - }; - - this.clearHit = function (options) { - var - context = options.context, - args = options.args, - data = options.data, - xScale = options.xScale, - width = options.lineWidth, - index = args.index, - x = xScale(args.x), - y = options.yScale(args.y), - x2; - - if (data.length - 1 > index) { - x2 = options.xScale(data[index + 1][0]); - context.clearRect(x - width, y - width, x2 - x + 2 * width, 2 * width); - } - }; - } - } - -}); - -/** Bars **/ -Flotr.addType('bars', { - - options: { - show: false, // => setting to true will show bars, false will hide - lineWidth: 2, // => in pixels - barWidth: 1, // => in units of the x axis - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillColor: null, // => fill color - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - horizontal: false, // => horizontal bars (x and y inverted) - stacked: false, // => stacked bar charts - centered: true, // => center the bars to their x axis value - topPadding: 0.1 // => top padding in percent - }, - - stack : { - positive : [], - negative : [], - _positive : [], // Shadow - _negative : [] // Shadow - }, - - draw : function (options) { - var - context = options.context; - - context.save(); - context.lineJoin = 'miter'; - // @TODO linewidth not interpreted the right way. - context.lineWidth = options.lineWidth; - context.strokeStyle = options.color; - if (options.fill) context.fillStyle = options.fillStyle; - - this.plot(options); - - context.restore(); - }, - - plot : function (options) { - - var - data = options.data, - context = options.context, - shadowSize = options.shadowSize, - i, geometry, left, top, width, height; - - if (data.length < 1) return; - - this.translate(context, options.horizontal); - - for (i = 0; i < data.length; i++) { - - geometry = this.getBarGeometry(data[i][0], data[i][1], options); - if (geometry === null) continue; - - left = geometry.left; - top = geometry.top; - width = geometry.width; - height = geometry.height; - - if (options.fill) context.fillRect(left, top, width, height); - if (shadowSize) { - context.save(); - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.fillRect(left + shadowSize, top + shadowSize, width, height); - context.restore(); - } - if (options.lineWidth) { - context.strokeRect(left, top, width, height); - } - } - }, - - translate : function (context, horizontal) { - if (horizontal) { - context.rotate(-Math.PI / 2); - context.scale(-1, 1); - } - }, - - getBarGeometry : function (x, y, options) { - - var - horizontal = options.horizontal, - barWidth = options.barWidth, - centered = options.centered, - stack = options.stacked ? this.stack : false, - lineWidth = options.lineWidth, - bisection = centered ? barWidth / 2 : 0, - xScale = horizontal ? options.yScale : options.xScale, - yScale = horizontal ? options.xScale : options.yScale, - xValue = horizontal ? y : x, - yValue = horizontal ? x : y, - stackOffset = 0, - stackValue, left, right, top, bottom; - - // Stacked bars - if (stack) { - stackValue = yValue > 0 ? stack.positive : stack.negative; - stackOffset = stackValue[xValue] || stackOffset; - stackValue[xValue] = stackOffset + yValue; - } - - left = xScale(xValue - bisection); - right = xScale(xValue + barWidth - bisection); - top = yScale(yValue + stackOffset); - bottom = yScale(stackOffset); - - // TODO for test passing... probably looks better without this - if (bottom < 0) bottom = 0; - - // TODO Skipping... - // if (right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) continue; - - return (x === null || y === null) ? null : { - x : xValue, - y : yValue, - xScale : xScale, - yScale : yScale, - top : top, - left : Math.min(left, right) - lineWidth / 2, - width : Math.abs(right - left) - lineWidth, - height : bottom - top - }; - }, - - hit : function (options) { - var - data = options.data, - args = options.args, - mouse = args[0], - n = args[1], - x = mouse.x, - y = mouse.y, - hitGeometry = this.getBarGeometry(x, y, options), - width = hitGeometry.width / 2, - left = hitGeometry.left, - geometry, i; - - for (i = data.length; i--;) { - geometry = this.getBarGeometry(data[i][0], data[i][1], options); - if (geometry.y > hitGeometry.y && Math.abs(left - geometry.left) < width) { - n.x = data[i][0]; - n.y = data[i][1]; - n.index = i; - n.seriesIndex = options.index; - } - } - }, - - drawHit : function (options) { - // TODO hits for stacked bars; implement using calculateStack option? - var - context = options.context, - args = options.args, - geometry = this.getBarGeometry(args.x, args.y, options), - left = geometry.left, - top = geometry.top, - width = geometry.width, - height = geometry.height; - - context.save(); - context.strokeStyle = options.color; - context.lineWidth = options.lineWidth; - this.translate(context, options.horizontal); - - // Draw highlight - context.beginPath(); - context.moveTo(left, top + height); - context.lineTo(left, top); - context.lineTo(left + width, top); - context.lineTo(left + width, top + height); - if (options.fill) { - context.fillStyle = options.fillStyle; - context.fill(); - } - context.stroke(); - context.closePath(); - - context.restore(); - }, - - clearHit: function (options) { - var - context = options.context, - args = options.args, - geometry = this.getBarGeometry(args.x, args.y, options), - left = geometry.left, - width = geometry.width, - top = geometry.top, - height = geometry.height, - lineWidth = 2 * options.lineWidth; - - context.save(); - this.translate(context, options.horizontal); - context.clearRect( - left - lineWidth, - Math.min(top, top + height) - lineWidth, - width + 2 * lineWidth, - Math.abs(height) + 2 * lineWidth - ); - context.restore(); - }, - - extendXRange : function (axis, data, options, bars) { - this._extendRange(axis, data, options, bars); - }, - - extendYRange : function (axis, data, options, bars) { - this._extendRange(axis, data, options, bars); - }, - _extendRange: function (axis, data, options, bars) { - - var - max = axis.options.max; - - if (_.isNumber(max) || _.isString(max)) return; - - var - newmin = axis.min, - newmax = axis.max, - horizontal = options.horizontal, - orientation = axis.orientation, - positiveSums = this.positiveSums || {}, - negativeSums = this.negativeSums || {}, - value, datum, index, j; - - // Sides of bars - if ((orientation == 1 && !horizontal) || (orientation == -1 && horizontal)) { - if (options.centered) { - newmax = Math.max(axis.datamax + options.barWidth, newmax); - newmin = Math.min(axis.datamin - options.barWidth, newmin); - } - } - - if (options.stacked && - ((orientation == 1 && horizontal) || (orientation == -1 && !horizontal))){ - - for (j = data.length; j--;) { - value = data[j][(orientation == 1 ? 1 : 0)]+''; - datum = data[j][(orientation == 1 ? 0 : 1)]; - - // Positive - if (datum > 0) { - positiveSums[value] = (positiveSums[value] || 0) + datum; - newmax = Math.max(newmax, positiveSums[value]); - } - - // Negative - else { - negativeSums[value] = (negativeSums[value] || 0) + datum; - newmin = Math.min(newmin, negativeSums[value]); - } - } - } - - // End of bars - if ((orientation == 1 && horizontal) || (orientation == -1 && !horizontal)) { - if (options.topPadding && (axis.max === axis.datamax || (options.stacked && this.stackMax !== newmax))) { - newmax += options.topPadding * (newmax - newmin); - } - } - - this.stackMin = newmin; - this.stackMax = newmax; - this.negativeSums = negativeSums; - this.positiveSums = positiveSums; - - axis.max = newmax; - axis.min = newmin; - } - -}); - -/** Bubbles **/ -Flotr.addType('bubbles', { - options: { - show: false, // => setting to true will show radar chart, false will hide - lineWidth: 2, // => line width in pixels - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - baseRadius: 2 // => ratio of the radar, against the plot size - }, - draw : function (options) { - var - context = options.context, - shadowSize = options.shadowSize; - - context.save(); - context.lineWidth = options.lineWidth; - - // Shadows - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.strokeStyle = 'rgba(0,0,0,0.05)'; - this.plot(options, shadowSize / 2); - context.strokeStyle = 'rgba(0,0,0,0.1)'; - this.plot(options, shadowSize / 4); - - // Chart - context.strokeStyle = options.color; - context.fillStyle = options.fillStyle; - this.plot(options); - - context.restore(); - }, - plot : function (options, offset) { - - var - data = options.data, - context = options.context, - geometry, - i, x, y, z; - - offset = offset || 0; - - for (i = 0; i < data.length; ++i){ - - geometry = this.getGeometry(data[i], options); - - context.beginPath(); - context.arc(geometry.x + offset, geometry.y + offset, geometry.z, 0, 2 * Math.PI, true); - context.stroke(); - if (options.fill) context.fill(); - context.closePath(); - } - }, - getGeometry : function (point, options) { - return { - x : options.xScale(point[0]), - y : options.yScale(point[1]), - z : point[2] * options.baseRadius - }; - }, - hit : function (options) { - var - data = options.data, - args = options.args, - mouse = args[0], - n = args[1], - x = mouse.x, - y = mouse.y, - geometry, - dx, dy; - - for (i = data.length; i--;) { - geometry = this.getGeometry(data[i], options); - - dx = geometry.x - options.xScale(x); - dy = geometry.y - options.yScale(y); - - if (Math.sqrt(dx * dx + dy * dy) < geometry.z) { - n.x = data[i][0]; - n.y = data[i][1]; - n.index = i; - n.seriesIndex = options.index; - } - } - }, - drawHit : function (options) { - - var - context = options.context, - geometry = this.getGeometry(options.data[options.args.index], options); - - context.save(); - context.lineWidth = options.lineWidth; - context.fillStyle = options.fillStyle; - context.strokeStyle = options.color; - context.beginPath(); - context.arc(geometry.x, geometry.y, geometry.z, 0, 2 * Math.PI, true); - context.fill(); - context.stroke(); - context.closePath(); - context.restore(); - }, - clearHit : function (options) { - - var - context = options.context, - geometry = this.getGeometry(options.data[options.args.index], options), - offset = geometry.z + options.lineWidth; - - context.save(); - context.clearRect( - geometry.x - offset, - geometry.y - offset, - 2 * offset, - 2 * offset - ); - context.restore(); - } - // TODO Add a hit calculation method (like pie) -}); - -/** Candles **/ -Flotr.addType('candles', { - options: { - show: false, // => setting to true will show candle sticks, false will hide - lineWidth: 1, // => in pixels - wickLineWidth: 1, // => in pixels - candleWidth: 0.6, // => in units of the x axis - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - upFillColor: '#00A8F0',// => up sticks fill color - downFillColor: '#CB4B4B',// => down sticks fill color - fillOpacity: 0.5, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - // TODO Test this barcharts option. - barcharts: false // => draw as barcharts (not standard bars but financial barcharts) - }, - - draw : function (options) { - - var - context = options.context; - - context.save(); - context.lineJoin = 'miter'; - context.lineCap = 'butt'; - // @TODO linewidth not interpreted the right way. - context.lineWidth = options.wickLineWidth || options.lineWidth; - - this.plot(options); - - context.restore(); - }, - - plot : function (options) { - - var - data = options.data, - context = options.context, - xScale = options.xScale, - yScale = options.yScale, - width = options.candleWidth / 2, - shadowSize = options.shadowSize, - lineWidth = options.lineWidth, - wickLineWidth = options.wickLineWidth, - pixelOffset = (wickLineWidth % 2) / 2, - color, - datum, x, y, - open, high, low, close, - left, right, bottom, top, bottom2, top2, - i; - - if (data.length < 1) return; - - for (i = 0; i < data.length; i++) { - datum = data[i]; - x = datum[0]; - open = datum[1]; - high = datum[2]; - low = datum[3]; - close = datum[4]; - left = xScale(x - width); - right = xScale(x + width); - bottom = yScale(low); - top = yScale(high); - bottom2 = yScale(Math.min(open, close)); - top2 = yScale(Math.max(open, close)); - - /* - // TODO skipping - if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) - continue; - */ - - color = options[open > close ? 'downFillColor' : 'upFillColor']; - - // Fill the candle. - // TODO Test the barcharts option - if (options.fill && !options.barcharts) { - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.fillRect(left + shadowSize, top2 + shadowSize, right - left, bottom2 - top2); - context.save(); - context.globalAlpha = options.fillOpacity; - context.fillStyle = color; - context.fillRect(left, top2 + lineWidth, right - left, bottom2 - top2); - context.restore(); - } - - // Draw candle outline/border, high, low. - if (lineWidth || wickLineWidth) { - - x = Math.floor((left + right) / 2) + pixelOffset; - - context.strokeStyle = color; - context.beginPath(); - - // TODO Again with the bartcharts - if (options.barcharts) { - - context.moveTo(x, Math.floor(top + width)); - context.lineTo(x, Math.floor(bottom + width)); - - y = Math.floor(open + width) + 0.5; - context.moveTo(Math.floor(left) + pixelOffset, y); - context.lineTo(x, y); - - y = Math.floor(close + width) + 0.5; - context.moveTo(Math.floor(right) + pixelOffset, y); - context.lineTo(x, y); - } else { - context.strokeRect(left, top2 + lineWidth, right - left, bottom2 - top2); - - context.moveTo(x, Math.floor(top2 + lineWidth)); - context.lineTo(x, Math.floor(top + lineWidth)); - context.moveTo(x, Math.floor(bottom2 + lineWidth)); - context.lineTo(x, Math.floor(bottom + lineWidth)); - } - - context.closePath(); - context.stroke(); - } - } - }, - extendXRange: function (axis, data, options) { - if (axis.options.max === null) { - axis.max = Math.max(axis.datamax + 0.5, axis.max); - axis.min = Math.min(axis.datamin - 0.5, axis.min); - } - } -}); - -/** Gantt - * Base on data in form [s,y,d] where: - * y - executor or simply y value - * s - task start value - * d - task duration - * **/ -Flotr.addType('gantt', { - options: { - show: false, // => setting to true will show gantt, false will hide - lineWidth: 2, // => in pixels - barWidth: 1, // => in units of the x axis - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillColor: null, // => fill color - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - centered: true // => center the bars to their x axis value - }, - /** - * Draws gantt series in the canvas element. - * @param {Object} series - Series with options.gantt.show = true. - */ - draw: function(series) { - var ctx = this.ctx, - bw = series.gantt.barWidth, - lw = Math.min(series.gantt.lineWidth, bw); - - ctx.save(); - ctx.translate(this.plotOffset.left, this.plotOffset.top); - ctx.lineJoin = 'miter'; - - /** - * @todo linewidth not interpreted the right way. - */ - ctx.lineWidth = lw; - ctx.strokeStyle = series.color; - - ctx.save(); - this.gantt.plotShadows(series, bw, 0, series.gantt.fill); - ctx.restore(); - - if(series.gantt.fill){ - var color = series.gantt.fillColor || series.color; - ctx.fillStyle = this.processColor(color, {opacity: series.gantt.fillOpacity}); - } - - this.gantt.plot(series, bw, 0, series.gantt.fill); - ctx.restore(); - }, - plot: function(series, barWidth, offset, fill){ - var data = series.data; - if(data.length < 1) return; - - var xa = series.xaxis, - ya = series.yaxis, - ctx = this.ctx, i; - - for(i = 0; i < data.length; i++){ - var y = data[i][0], - s = data[i][1], - d = data[i][2], - drawLeft = true, drawTop = true, drawRight = true; - - if (s === null || d === null) continue; - - var left = s, - right = s + d, - bottom = y - (series.gantt.centered ? barWidth/2 : 0), - top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0); - - if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) - continue; - - if(left < xa.min){ - left = xa.min; - drawLeft = false; - } - - if(right > xa.max){ - right = xa.max; - if (xa.lastSerie != series) - drawTop = false; - } - - if(bottom < ya.min) - bottom = ya.min; - - if(top > ya.max){ - top = ya.max; - if (ya.lastSerie != series) - drawTop = false; - } - - /** - * Fill the bar. - */ - if(fill){ - ctx.beginPath(); - ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset); - ctx.lineTo(xa.d2p(left), ya.d2p(top) + offset); - ctx.lineTo(xa.d2p(right), ya.d2p(top) + offset); - ctx.lineTo(xa.d2p(right), ya.d2p(bottom) + offset); - ctx.fill(); - ctx.closePath(); - } - - /** - * Draw bar outline/border. - */ - if(series.gantt.lineWidth && (drawLeft || drawRight || drawTop)){ - ctx.beginPath(); - ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset); - - ctx[drawLeft ?'lineTo':'moveTo'](xa.d2p(left), ya.d2p(top) + offset); - ctx[drawTop ?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(top) + offset); - ctx[drawRight?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(bottom) + offset); - - ctx.stroke(); - ctx.closePath(); - } - } - }, - plotShadows: function(series, barWidth, offset){ - var data = series.data; - if(data.length < 1) return; - - var i, y, s, d, - xa = series.xaxis, - ya = series.yaxis, - ctx = this.ctx, - sw = this.options.shadowSize; - - for(i = 0; i < data.length; i++){ - y = data[i][0]; - s = data[i][1]; - d = data[i][2]; - - if (s === null || d === null) continue; - - var left = s, - right = s + d, - bottom = y - (series.gantt.centered ? barWidth/2 : 0), - top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0); - - if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) - continue; - - if(left < xa.min) left = xa.min; - if(right > xa.max) right = xa.max; - if(bottom < ya.min) bottom = ya.min; - if(top > ya.max) top = ya.max; - - var width = xa.d2p(right)-xa.d2p(left)-((xa.d2p(right)+sw <= this.plotWidth) ? 0 : sw); - var height = ya.d2p(bottom)-ya.d2p(top)-((ya.d2p(bottom)+sw <= this.plotHeight) ? 0 : sw ); - - ctx.fillStyle = 'rgba(0,0,0,0.05)'; - ctx.fillRect(Math.min(xa.d2p(left)+sw, this.plotWidth), Math.min(ya.d2p(top)+sw, this.plotHeight), width, height); - } - }, - extendXRange: function(axis) { - if(axis.options.max === null){ - var newmin = axis.min, - newmax = axis.max, - i, j, x, s, g, - stackedSumsPos = {}, - stackedSumsNeg = {}, - lastSerie = null; - - for(i = 0; i < this.series.length; ++i){ - s = this.series[i]; - g = s.gantt; - - if(g.show && s.xaxis == axis) { - for (j = 0; j < s.data.length; j++) { - if (g.show) { - y = s.data[j][0]+''; - stackedSumsPos[y] = Math.max((stackedSumsPos[y] || 0), s.data[j][1]+s.data[j][2]); - lastSerie = s; - } - } - for (j in stackedSumsPos) { - newmax = Math.max(stackedSumsPos[j], newmax); - } - } - } - axis.lastSerie = lastSerie; - axis.max = newmax; - axis.min = newmin; - } - }, - extendYRange: function(axis){ - if(axis.options.max === null){ - var newmax = Number.MIN_VALUE, - newmin = Number.MAX_VALUE, - i, j, s, g, - stackedSumsPos = {}, - stackedSumsNeg = {}, - lastSerie = null; - - for(i = 0; i < this.series.length; ++i){ - s = this.series[i]; - g = s.gantt; - - if (g.show && !s.hide && s.yaxis == axis) { - var datamax = Number.MIN_VALUE, datamin = Number.MAX_VALUE; - for(j=0; j < s.data.length; j++){ - datamax = Math.max(datamax,s.data[j][0]); - datamin = Math.min(datamin,s.data[j][0]); - } - - if (g.centered) { - newmax = Math.max(datamax + 0.5, newmax); - newmin = Math.min(datamin - 0.5, newmin); - } - else { - newmax = Math.max(datamax + 1, newmax); - newmin = Math.min(datamin, newmin); - } - // For normal horizontal bars - if (g.barWidth + datamax > newmax){ - newmax = axis.max + g.barWidth; - } - } - } - axis.lastSerie = lastSerie; - axis.max = newmax; - axis.min = newmin; - axis.tickSize = Flotr.getTickSize(axis.options.noTicks, newmin, newmax, axis.options.tickDecimals); - } - } -}); - -/** Markers **/ -/** - * Formats the marker labels. - * @param {Object} obj - Marker value Object {x:..,y:..} - * @return {String} Formatted marker string - */ -(function () { - -Flotr.defaultMarkerFormatter = function(obj){ - return (Math.round(obj.y*100)/100)+''; -}; - -Flotr.addType('markers', { - options: { - show: false, // => setting to true will show markers, false will hide - lineWidth: 1, // => line width of the rectangle around the marker - color: '#000000', // => text color - fill: false, // => fill or not the marekers' rectangles - fillColor: "#FFFFFF", // => fill color - fillOpacity: 0.4, // => fill opacity - stroke: false, // => draw the rectangle around the markers - position: 'ct', // => the markers position (vertical align: b, m, t, horizontal align: l, c, r) - verticalMargin: 0, // => the margin between the point and the text. - labelFormatter: Flotr.defaultMarkerFormatter, - fontSize: Flotr.defaultOptions.fontSize, - stacked: false, // => true if markers should be stacked - stackingType: 'b', // => define staching behavior, (b- bars like, a - area like) (see Issue 125 for details) - horizontal: false // => true if markers should be horizontal (For now only in a case on horizontal stacked bars, stacks should be calculated horizontaly) - }, - - // TODO test stacked markers. - stack : { - positive : [], - negative : [], - values : [] - }, - - draw : function (options) { - - var - data = options.data, - context = options.context, - stack = options.stacked ? options.stack : false, - stackType = options.stackingType, - stackOffsetNeg, - stackOffsetPos, - stackOffset, - i, x, y, label; - - context.save(); - context.lineJoin = 'round'; - context.lineWidth = options.lineWidth; - context.strokeStyle = 'rgba(0,0,0,0.5)'; - context.fillStyle = options.fillStyle; - - function stackPos (a, b) { - stackOffsetPos = stack.negative[a] || 0; - stackOffsetNeg = stack.positive[a] || 0; - if (b > 0) { - stack.positive[a] = stackOffsetPos + b; - return stackOffsetPos + b; - } else { - stack.negative[a] = stackOffsetNeg + b; - return stackOffsetNeg + b; - } - } - - for (i = 0; i < data.length; ++i) { - - x = data[i][0]; - y = data[i][1]; - - if (stack) { - if (stackType == 'b') { - if (options.horizontal) y = stackPos(y, x); - else x = stackPos(x, y); - } else if (stackType == 'a') { - stackOffset = stack.values[x] || 0; - stack.values[x] = stackOffset + y; - y = stackOffset + y; - } - } - - label = options.labelFormatter({x: x, y: y, index: i, data : data}); - this.plot(options.xScale(x), options.yScale(y), label, options); - } - context.restore(); - }, - plot: function(x, y, label, options) { - var context = options.context; - if (isImage(label) && !label.complete) { - throw 'Marker image not loaded.'; - } else { - this._plot(x, y, label, options); - } - }, - - _plot: function(x, y, label, options) { - var context = options.context, - margin = 2, - left = x, - top = y, - dim; - - if (isImage(label)) - dim = {height : label.height, width: label.width}; - else - dim = options.text.canvas(label); - - dim.width = Math.floor(dim.width+margin*2); - dim.height = Math.floor(dim.height+margin*2); - - if (options.position.indexOf('c') != -1) left -= dim.width/2 + margin; - else if (options.position.indexOf('l') != -1) left -= dim.width; - - if (options.position.indexOf('m') != -1) top -= dim.height/2 + margin; - else if (options.position.indexOf('t') != -1) top -= dim.height + options.verticalMargin; - else top += options.verticalMargin; - - left = Math.floor(left)+0.5; - top = Math.floor(top)+0.5; - - if(options.fill) - context.fillRect(left, top, dim.width, dim.height); - - if(options.stroke) - context.strokeRect(left, top, dim.width, dim.height); - - if (isImage(label)) - context.drawImage(label, left+margin, top+margin); - else - Flotr.drawText(context, label, left+margin, top+margin, {textBaseline: 'top', textAlign: 'left', size: options.fontSize, color: options.color}); - } -}); - -function isImage (i) { - return typeof i === 'object' && i.constructor && (Image ? true : i.constructor === Image); -} - -})(); - -/** Pie **/ -/** - * Formats the pies labels. - * @param {Object} slice - Slice object - * @return {String} Formatted pie label string - */ -(function () { - -var - _ = Flotr._; - -Flotr.defaultPieLabelFormatter = function (total, value) { - return (100 * value / total).toFixed(2)+'%'; -}; - -Flotr.addType('pie', { - options: { - show: false, // => setting to true will show bars, false will hide - lineWidth: 1, // => in pixels - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillColor: null, // => fill color - fillOpacity: 0.6, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - explode: 6, // => the number of pixels the splices will be far from the center - sizeRatio: 0.6, // => the size ratio of the pie relative to the plot - startAngle: Math.PI/4, // => the first slice start angle - labelFormatter: Flotr.defaultPieLabelFormatter, - pie3D: false, // => whether to draw the pie in 3 dimenstions or not (ineffective) - pie3DviewAngle: (Math.PI/2 * 0.8), - pie3DspliceThickness: 20 - }, - - draw : function (options) { - - // TODO 3D charts what? - - var - data = options.data, - context = options.context, - canvas = context.canvas, - lineWidth = options.lineWidth, - shadowSize = options.shadowSize, - sizeRatio = options.sizeRatio, - height = options.height, - width = options.width, - explode = options.explode, - color = options.color, - fill = options.fill, - fillStyle = options.fillStyle, - radius = Math.min(canvas.width, canvas.height) * sizeRatio / 2, - value = data[0][1], - html = [], - vScale = 1,//Math.cos(series.pie.viewAngle); - measure = Math.PI * 2 * value / this.total, - startAngle = this.startAngle || (2 * Math.PI * options.startAngle), // TODO: this initial startAngle is already in radians (fixing will be test-unstable) - endAngle = startAngle + measure, - bisection = startAngle + measure / 2, - label = options.labelFormatter(this.total, value), - //plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale; - explodeCoeff = explode + radius + 4, - distX = Math.cos(bisection) * explodeCoeff, - distY = Math.sin(bisection) * explodeCoeff, - textAlign = distX < 0 ? 'right' : 'left', - textBaseline = distY > 0 ? 'top' : 'bottom', - style, - x, y, - distX, distY; - - context.save(); - context.translate(width / 2, height / 2); - context.scale(1, vScale); - - x = Math.cos(bisection) * explode; - y = Math.sin(bisection) * explode; - - // Shadows - if (shadowSize > 0) { - this.plotSlice(x + shadowSize, y + shadowSize, radius, startAngle, endAngle, context); - if (fill) { - context.fillStyle = 'rgba(0,0,0,0.1)'; - context.fill(); - } - } - - this.plotSlice(x, y, radius, startAngle, endAngle, context); - if (fill) { - context.fillStyle = fillStyle; - context.fill(); - } - context.lineWidth = lineWidth; - context.strokeStyle = color; - context.stroke(); - - style = { - size : options.fontSize * 1.2, - color : options.fontColor, - weight : 1.5 - }; - - if (label) { - if (options.htmlText || !options.textEnabled) { - divStyle = 'position:absolute;' + textBaseline + ':' + (height / 2 + (textBaseline === 'top' ? distY : -distY)) + 'px;'; - divStyle += textAlign + ':' + (width / 2 + (textAlign === 'right' ? -distX : distX)) + 'px;'; - html.push('
    ', label, '
    '); - } - else { - style.textAlign = textAlign; - style.textBaseline = textBaseline; - Flotr.drawText(context, label, distX, distY, style); - } - } - - if (options.htmlText || !options.textEnabled) { - var div = Flotr.DOM.node('
    '); - Flotr.DOM.insert(div, html.join('')); - Flotr.DOM.insert(options.element, div); - } - - context.restore(); - - // New start angle - this.startAngle = endAngle; - this.slices = this.slices || []; - this.slices.push({ - radius : Math.min(canvas.width, canvas.height) * sizeRatio / 2, - x : x, - y : y, - explode : explode, - start : startAngle, - end : endAngle - }); - }, - plotSlice : function (x, y, radius, startAngle, endAngle, context) { - context.beginPath(); - context.moveTo(x, y); - context.arc(x, y, radius, startAngle, endAngle, false); - context.lineTo(x, y); - context.closePath(); - }, - hit : function (options) { - - var - data = options.data[0], - args = options.args, - index = options.index, - mouse = args[0], - n = args[1], - slice = this.slices[index], - x = mouse.relX - options.width / 2, - y = mouse.relY - options.height / 2, - r = Math.sqrt(x * x + y * y), - theta = Math.atan(y / x), - circle = Math.PI * 2, - explode = slice.explode || options.explode, - start = slice.start % circle, - end = slice.end % circle; - - if (x < 0) { - theta += Math.PI; - } else if (x > 0 && y < 0) { - theta += circle; - } - - if (r < slice.radius + explode && r > explode) { - if ((start > end && (theta < end || theta > start)) || - (theta > start && theta < end)) { - - // TODO Decouple this from hit plugin (chart shouldn't know what n means) - n.x = data[0]; - n.y = data[1]; - n.sAngle = start; - n.eAngle = end; - n.index = 0; - n.seriesIndex = index; - n.fraction = data[1] / this.total; - } - } - }, - drawHit: function (options) { - var - context = options.context, - slice = this.slices[options.args.seriesIndex]; - - context.save(); - context.translate(options.width / 2, options.height / 2); - this.plotSlice(slice.x, slice.y, slice.radius, slice.start, slice.end, context); - context.stroke(); - context.restore(); - }, - clearHit : function (options) { - var - context = options.context, - slice = this.slices[options.args.seriesIndex], - padding = 2 * options.lineWidth, - radius = slice.radius + padding; - - context.save(); - context.translate(options.width / 2, options.height / 2); - context.clearRect( - slice.x - radius, - slice.y - radius, - 2 * radius + padding, - 2 * radius + padding - ); - context.restore(); - }, - extendYRange : function (axis, data) { - this.total = (this.total || 0) + data[0][1]; - } -}); -})(); - -/** Points **/ -Flotr.addType('points', { - options: { - show: false, // => setting to true will show points, false will hide - radius: 3, // => point radius (pixels) - lineWidth: 2, // => line width in pixels - fill: true, // => true to fill the points with a color, false for (transparent) no fill - fillColor: '#FFFFFF', // => fill color - fillOpacity: 0.4 // => opacity of color inside the points - }, - - draw : function (options) { - var - context = options.context, - lineWidth = options.lineWidth, - shadowSize = options.shadowSize; - - context.save(); - - if (shadowSize > 0) { - context.lineWidth = shadowSize / 2; - - context.strokeStyle = 'rgba(0,0,0,0.1)'; - this.plot(options, shadowSize / 2 + context.lineWidth / 2); - - context.strokeStyle = 'rgba(0,0,0,0.2)'; - this.plot(options, context.lineWidth / 2); - } - - context.lineWidth = options.lineWidth; - context.strokeStyle = options.color; - context.fillStyle = options.fillColor || options.color; - - this.plot(options); - context.restore(); - }, - - plot : function (options, offset) { - var - data = options.data, - context = options.context, - xScale = options.xScale, - yScale = options.yScale, - i, x, y; - - for (i = data.length - 1; i > -1; --i) { - y = data[i][1]; - if (y === null) continue; - - x = xScale(data[i][0]); - y = yScale(y); - - if (x < 0 || x > options.width || y < 0 || y > options.height) continue; - - context.beginPath(); - if (offset) { - context.arc(x, y + offset, options.radius, 0, Math.PI, false); - } else { - context.arc(x, y, options.radius, 0, 2 * Math.PI, true); - if (options.fill) context.fill(); - } - context.stroke(); - context.closePath(); - } - } -}); - -/** Radar **/ -Flotr.addType('radar', { - options: { - show: false, // => setting to true will show radar chart, false will hide - lineWidth: 2, // => line width in pixels - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - radiusRatio: 0.90 // => ratio of the radar, against the plot size - }, - draw : function (options) { - var - context = options.context, - shadowSize = options.shadowSize; - - context.save(); - context.translate(options.width / 2, options.height / 2); - context.lineWidth = options.lineWidth; - - // Shadow - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.strokeStyle = 'rgba(0,0,0,0.05)'; - this.plot(options, shadowSize / 2); - context.strokeStyle = 'rgba(0,0,0,0.1)'; - this.plot(options, shadowSize / 4); - - // Chart - context.strokeStyle = options.color; - context.fillStyle = options.fillStyle; - this.plot(options); - - context.restore(); - }, - plot : function (options, offset) { - var - data = options.data, - context = options.context, - radius = Math.min(options.height, options.width) * options.radiusRatio / 2, - step = 2 * Math.PI / data.length, - angle = -Math.PI / 2, - i, ratio; - - offset = offset || 0; - - context.beginPath(); - for (i = 0; i < data.length; ++i) { - ratio = data[i][1] / this.max; - - context[i === 0 ? 'moveTo' : 'lineTo']( - Math.cos(i * step + angle) * radius * ratio + offset, - Math.sin(i * step + angle) * radius * ratio + offset - ); - } - context.closePath(); - if (options.fill) context.fill(); - context.stroke(); - }, - extendYRange : function (axis, data) { - this.max = Math.max(axis.max, this.max || -Number.MAX_VALUE); - } -}); - -Flotr.addType('timeline', { - options: { - show: false, - lineWidth: 1, - barWidth: 0.2, - fill: true, - fillColor: null, - fillOpacity: 0.4, - centered: true - }, - - draw : function (options) { - - var - context = options.context; - - context.save(); - context.lineJoin = 'miter'; - context.lineWidth = options.lineWidth; - context.strokeStyle = options.color; - context.fillStyle = options.fillStyle; - - this.plot(options); - - context.restore(); - }, - - plot : function (options) { - - var - data = options.data, - context = options.context, - xScale = options.xScale, - yScale = options.yScale, - barWidth = options.barWidth, - lineWidth = options.lineWidth, - i; - - Flotr._.each(data, function (timeline) { - - var - x = timeline[0], - y = timeline[1], - w = timeline[2], - h = barWidth, - - xt = Math.ceil(xScale(x)), - wt = Math.ceil(xScale(x + w)) - xt, - yt = Math.round(yScale(y)), - ht = Math.round(yScale(y - h)) - yt, - - x0 = xt - lineWidth / 2, - y0 = Math.round(yt - ht / 2) - lineWidth / 2; - - context.strokeRect(x0, y0, wt, ht); - context.fillRect(x0, y0, wt, ht); - - }); - }, - - extendRange : function (series) { - - var - data = series.data, - xa = series.xaxis, - ya = series.yaxis, - w = series.timeline.barWidth; - - if (xa.options.min === null) - xa.min = xa.datamin - w / 2; - - if (xa.options.max === null) { - - var - max = xa.max; - - Flotr._.each(data, function (timeline) { - max = Math.max(max, timeline[0] + timeline[2]); - }, this); - - xa.max = max + w / 2; - } - - if (ya.options.min === null) - ya.min = ya.datamin - w; - if (ya.options.min === null) - ya.max = ya.datamax + w; - } - -}); - -(function () { - -var D = Flotr.DOM; - -Flotr.addPlugin('crosshair', { - options: { - mode: null, // => one of null, 'x', 'y' or 'xy' - color: '#FF0000', // => crosshair color - hideCursor: true // => hide the cursor when the crosshair is shown - }, - callbacks: { - 'flotr:mousemove': function(e, pos) { - if (this.options.crosshair.mode) { - this.crosshair.clearCrosshair(); - this.crosshair.drawCrosshair(pos); - } - } - }, - /** - * Draws the selection box. - */ - drawCrosshair: function(pos) { - var octx = this.octx, - options = this.options.crosshair, - plotOffset = this.plotOffset, - x = plotOffset.left + pos.relX + 0.5, - y = plotOffset.top + pos.relY + 0.5; - - if (pos.relX < 0 || pos.relY < 0 || pos.relX > this.plotWidth || pos.relY > this.plotHeight) { - this.el.style.cursor = null; - D.removeClass(this.el, 'flotr-crosshair'); - return; - } - - if (options.hideCursor) { - this.el.style.cursor = 'none'; - D.addClass(this.el, 'flotr-crosshair'); - } - - octx.save(); - octx.strokeStyle = options.color; - octx.lineWidth = 1; - octx.beginPath(); - - if (options.mode.indexOf('x') != -1) { - octx.moveTo(x, plotOffset.top); - octx.lineTo(x, plotOffset.top + this.plotHeight); - } - - if (options.mode.indexOf('y') != -1) { - octx.moveTo(plotOffset.left, y); - octx.lineTo(plotOffset.left + this.plotWidth, y); - } - - octx.stroke(); - octx.restore(); - }, - /** - * Removes the selection box from the overlay canvas. - */ - clearCrosshair: function() { - - var - plotOffset = this.plotOffset, - position = this.lastMousePos, - context = this.octx; - - if (position) { - context.clearRect( - position.relX + plotOffset.left, - plotOffset.top, - 1, - this.plotHeight + 1 - ); - context.clearRect( - plotOffset.left, - position.relY + plotOffset.top, - this.plotWidth + 1, - 1 - ); - } - } -}); -})(); - -(function() { - -var - D = Flotr.DOM, - _ = Flotr._; - -function getImage (type, canvas, width, height) { - - // TODO add scaling for w / h - var - mime = 'image/'+type, - data = canvas.toDataURL(mime), - image = new Image(); - image.src = data; - return image; -} - -Flotr.addPlugin('download', { - - saveImage: function (type, width, height, replaceCanvas) { - var image = null; - if (Flotr.isIE && Flotr.isIE < 9) { - image = ''+this.canvas.firstChild.innerHTML+''; - return window.open().document.write(image); - } - - if (type !== 'jpeg' && type !== 'png') return; - - image = getImage(type, this.canvas, width, height); - - if (_.isElement(image) && replaceCanvas) { - this.download.restoreCanvas(); - D.hide(this.canvas); - D.hide(this.overlay); - D.setStyles({position: 'absolute'}); - D.insert(this.el, image); - this.saveImageElement = image; - } else { - return window.open(image.src); - } - }, - - restoreCanvas: function() { - D.show(this.canvas); - D.show(this.overlay); - if (this.saveImageElement) this.el.removeChild(this.saveImageElement); - this.saveImageElement = null; - } -}); - -})(); - -(function () { - -var E = Flotr.EventAdapter, - _ = Flotr._; - -Flotr.addPlugin('graphGrid', { - - callbacks: { - 'flotr:beforedraw' : function () { - this.graphGrid.drawGrid(); - }, - 'flotr:afterdraw' : function () { - this.graphGrid.drawOutline(); - } - }, - - drawGrid: function(){ - - var - ctx = this.ctx, - options = this.options, - grid = options.grid, - verticalLines = grid.verticalLines, - horizontalLines = grid.horizontalLines, - minorVerticalLines = grid.minorVerticalLines, - minorHorizontalLines = grid.minorHorizontalLines, - plotHeight = this.plotHeight, - plotWidth = this.plotWidth, - a, v, i, j; - - if(verticalLines || minorVerticalLines || - horizontalLines || minorHorizontalLines){ - E.fire(this.el, 'flotr:beforegrid', [this.axes.x, this.axes.y, options, this]); - } - ctx.save(); - ctx.lineWidth = 1; - ctx.strokeStyle = grid.tickColor; - - function circularHorizontalTicks (ticks) { - for(i = 0; i < ticks.length; ++i){ - var ratio = ticks[i].v / a.max; - for(j = 0; j <= sides; ++j){ - ctx[j === 0 ? 'moveTo' : 'lineTo']( - Math.cos(j*coeff+angle)*radius*ratio, - Math.sin(j*coeff+angle)*radius*ratio - ); - } - } - } - function drawGridLines (ticks, callback) { - _.each(_.pluck(ticks, 'v'), function(v){ - // Don't show lines on upper and lower bounds. - if ((v <= a.min || v >= a.max) || - (v == a.min || v == a.max) && grid.outlineWidth) - return; - callback(Math.floor(a.d2p(v)) + ctx.lineWidth/2); - }); - } - function drawVerticalLines (x) { - ctx.moveTo(x, 0); - ctx.lineTo(x, plotHeight); - } - function drawHorizontalLines (y) { - ctx.moveTo(0, y); - ctx.lineTo(plotWidth, y); - } - - if (grid.circular) { - ctx.translate(this.plotOffset.left+plotWidth/2, this.plotOffset.top+plotHeight/2); - var radius = Math.min(plotHeight, plotWidth)*options.radar.radiusRatio/2, - sides = this.axes.x.ticks.length, - coeff = 2*(Math.PI/sides), - angle = -Math.PI/2; - - // Draw grid lines in vertical direction. - ctx.beginPath(); - - a = this.axes.y; - - if(horizontalLines){ - circularHorizontalTicks(a.ticks); - } - if(minorHorizontalLines){ - circularHorizontalTicks(a.minorTicks); - } - - if(verticalLines){ - _.times(sides, function(i){ - ctx.moveTo(0, 0); - ctx.lineTo(Math.cos(i*coeff+angle)*radius, Math.sin(i*coeff+angle)*radius); - }); - } - ctx.stroke(); - } - else { - ctx.translate(this.plotOffset.left, this.plotOffset.top); - - // Draw grid background, if present in options. - if(grid.backgroundColor){ - ctx.fillStyle = this.processColor(grid.backgroundColor, {x1: 0, y1: 0, x2: plotWidth, y2: plotHeight}); - ctx.fillRect(0, 0, plotWidth, plotHeight); - } - - ctx.beginPath(); - - a = this.axes.x; - if (verticalLines) drawGridLines(a.ticks, drawVerticalLines); - if (minorVerticalLines) drawGridLines(a.minorTicks, drawVerticalLines); - - a = this.axes.y; - if (horizontalLines) drawGridLines(a.ticks, drawHorizontalLines); - if (minorHorizontalLines) drawGridLines(a.minorTicks, drawHorizontalLines); - - ctx.stroke(); - } - - ctx.restore(); - if(verticalLines || minorVerticalLines || - horizontalLines || minorHorizontalLines){ - E.fire(this.el, 'flotr:aftergrid', [this.axes.x, this.axes.y, options, this]); - } - }, - - drawOutline: function(){ - var - that = this, - options = that.options, - grid = options.grid, - outline = grid.outline, - ctx = that.ctx, - backgroundImage = grid.backgroundImage, - plotOffset = that.plotOffset, - leftOffset = plotOffset.left, - topOffset = plotOffset.top, - plotWidth = that.plotWidth, - plotHeight = that.plotHeight, - v, img, src, left, top, globalAlpha; - - if (!grid.outlineWidth) return; - - ctx.save(); - - if (grid.circular) { - ctx.translate(leftOffset + plotWidth / 2, topOffset + plotHeight / 2); - var radius = Math.min(plotHeight, plotWidth) * options.radar.radiusRatio / 2, - sides = this.axes.x.ticks.length, - coeff = 2*(Math.PI/sides), - angle = -Math.PI/2; - - // Draw axis/grid border. - ctx.beginPath(); - ctx.lineWidth = grid.outlineWidth; - ctx.strokeStyle = grid.color; - ctx.lineJoin = 'round'; - - for(i = 0; i <= sides; ++i){ - ctx[i === 0 ? 'moveTo' : 'lineTo'](Math.cos(i*coeff+angle)*radius, Math.sin(i*coeff+angle)*radius); - } - //ctx.arc(0, 0, radius, 0, Math.PI*2, true); - - ctx.stroke(); - } - else { - ctx.translate(leftOffset, topOffset); - - // Draw axis/grid border. - var lw = grid.outlineWidth, - orig = 0.5-lw+((lw+1)%2/2), - lineTo = 'lineTo', - moveTo = 'moveTo'; - ctx.lineWidth = lw; - ctx.strokeStyle = grid.color; - ctx.lineJoin = 'miter'; - ctx.beginPath(); - ctx.moveTo(orig, orig); - plotWidth = plotWidth - (lw / 2) % 1; - plotHeight = plotHeight + lw / 2; - ctx[outline.indexOf('n') !== -1 ? lineTo : moveTo](plotWidth, orig); - ctx[outline.indexOf('e') !== -1 ? lineTo : moveTo](plotWidth, plotHeight); - ctx[outline.indexOf('s') !== -1 ? lineTo : moveTo](orig, plotHeight); - ctx[outline.indexOf('w') !== -1 ? lineTo : moveTo](orig, orig); - ctx.stroke(); - ctx.closePath(); - } - - ctx.restore(); - - if (backgroundImage) { - - src = backgroundImage.src || backgroundImage; - left = (parseInt(backgroundImage.left, 10) || 0) + plotOffset.left; - top = (parseInt(backgroundImage.top, 10) || 0) + plotOffset.top; - img = new Image(); - - img.onload = function() { - ctx.save(); - if (backgroundImage.alpha) ctx.globalAlpha = backgroundImage.alpha; - ctx.globalCompositeOperation = 'destination-over'; - ctx.drawImage(img, 0, 0, img.width, img.height, left, top, plotWidth, plotHeight); - ctx.restore(); - }; - - img.src = src; - } - } -}); - -})(); - -(function () { - -var - D = Flotr.DOM, - _ = Flotr._, - flotr = Flotr, - S_MOUSETRACK = '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;'; - -Flotr.addPlugin('hit', { - callbacks: { - 'flotr:mousemove': function(e, pos) { - this.hit.track(pos); - }, - 'flotr:click': function(pos) { - this.hit.track(pos); - }, - 'flotr:mouseout': function() { - this.hit.clearHit(); - } - }, - track : function (pos) { - if (this.options.mouse.track || _.any(this.series, function(s){return s.mouse && s.mouse.track;})) { - this.hit.hit(pos); - } - }, - /** - * Try a method on a graph type. If the method exists, execute it. - * @param {Object} series - * @param {String} method Method name. - * @param {Array} args Arguments applied to method. - * @return executed successfully or failed. - */ - executeOnType: function(s, method, args){ - var - success = false, - options; - - if (!_.isArray(s)) s = [s]; - - function e(s, index) { - _.each(_.keys(flotr.graphTypes), function (type) { - if (s[type] && s[type].show && this[type][method]) { - options = this.getOptions(s, type); - - options.fill = !!s.mouse.fillColor; - options.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity}); - options.color = s.mouse.lineColor; - options.context = this.octx; - options.index = index; - - if (args) options.args = args; - this[type][method].call(this[type], options); - success = true; - } - }, this); - } - _.each(s, e, this); - - return success; - }, - /** - * Updates the mouse tracking point on the overlay. - */ - drawHit: function(n){ - var octx = this.octx, - s = n.series; - - if (s.mouse.lineColor) { - octx.save(); - octx.lineWidth = (s.points ? s.points.lineWidth : 1); - octx.strokeStyle = s.mouse.lineColor; - octx.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity}); - octx.translate(this.plotOffset.left, this.plotOffset.top); - - if (!this.hit.executeOnType(s, 'drawHit', n)) { - var xa = n.xaxis, - ya = n.yaxis; - - octx.beginPath(); - // TODO fix this (points) should move to general testable graph mixin - octx.arc(xa.d2p(n.x), ya.d2p(n.y), s.points.radius || s.mouse.radius, 0, 2 * Math.PI, true); - octx.fill(); - octx.stroke(); - octx.closePath(); - } - octx.restore(); - } - this.prevHit = n; - }, - /** - * Removes the mouse tracking point from the overlay. - */ - clearHit: function(){ - var prev = this.prevHit, - octx = this.octx, - plotOffset = this.plotOffset; - octx.save(); - octx.translate(plotOffset.left, plotOffset.top); - if (prev) { - if (!this.hit.executeOnType(prev.series, 'clearHit', this.prevHit)) { - // TODO fix this (points) should move to general testable graph mixin - var - s = prev.series, - lw = (s.points ? s.points.lineWidth : 1); - offset = (s.points.radius || s.mouse.radius) + lw; - octx.clearRect( - prev.xaxis.d2p(prev.x) - offset, - prev.yaxis.d2p(prev.y) - offset, - offset*2, - offset*2 - ); - } - D.hide(this.mouseTrack); - this.prevHit = null; - } - octx.restore(); - }, - /** - * Retrieves the nearest data point from the mouse cursor. If it's within - * a certain range, draw a point on the overlay canvas and display the x and y - * value of the data. - * @param {Object} mouse - Object that holds the relative x and y coordinates of the cursor. - */ - hit: function(mouse){ - - var - options = this.options, - prevHit = this.prevHit, - closest, sensibility, dataIndex, seriesIndex, series, value, xaxis, yaxis; - - if (this.series.length === 0) return; - - // Nearest data element. - // dist, x, y, relX, relY, absX, absY, sAngle, eAngle, fraction, mouse, - // xaxis, yaxis, series, index, seriesIndex - n = { - relX : mouse.relX, - relY : mouse.relY, - absX : mouse.absX, - absY : mouse.absY - }; - - if (options.mouse.trackY && - !options.mouse.trackAll && - this.hit.executeOnType(this.series, 'hit', [mouse, n])) - { - - if (!_.isUndefined(n.seriesIndex)) { - series = this.series[n.seriesIndex]; - n.series = series; - n.mouse = series.mouse; - n.xaxis = series.xaxis; - n.yaxis = series.yaxis; - } - } else { - - closest = this.hit.closest(mouse); - - if (closest) { - - closest = options.mouse.trackY ? closest.point : closest.x; - seriesIndex = closest.seriesIndex; - series = this.series[seriesIndex]; - xaxis = series.xaxis; - yaxis = series.yaxis; - sensibility = 2 * series.mouse.sensibility; - - if - (options.mouse.trackAll || - (closest.distanceX < sensibility / xaxis.scale && - (!options.mouse.trackY || closest.distanceY < sensibility / yaxis.scale))) - { - n.series = series; - n.xaxis = series.xaxis; - n.yaxis = series.yaxis; - n.mouse = series.mouse; - n.x = closest.x; - n.y = closest.y; - n.dist = closest.distance; - n.index = closest.dataIndex; - n.seriesIndex = seriesIndex; - } - } - } - - if (!prevHit || (prevHit.index !== n.index || prevHit.seriesIndex !== n.seriesIndex)) { - this.hit.clearHit(); - if (n.series && n.mouse && n.mouse.track) { - this.hit.drawMouseTrack(n); - this.hit.drawHit(n); - Flotr.EventAdapter.fire(this.el, 'flotr:hit', [n, this]); - } - } - }, - - closest : function (mouse) { - - var - series = this.series, - options = this.options, - mouseX = mouse.x, - mouseY = mouse.y, - compare = Number.MAX_VALUE, - compareX = Number.MAX_VALUE, - closest = {}, - closestX = {}, - check = false, - serie, data, - distance, distanceX, distanceY, - x, y, i, j; - - function setClosest (o) { - o.distance = distance; - o.distanceX = distanceX; - o.distanceY = distanceY; - o.seriesIndex = i; - o.dataIndex = j; - o.x = x; - o.y = y; - } - - for (i = 0; i < series.length; i++) { - - serie = series[i]; - data = serie.data; - - if (data.length) check = true; - - for (j = data.length; j--;) { - - x = data[j][0]; - y = data[j][1]; - - if (x === null || y === null) continue; - - // don't check if the point isn't visible in the current range - if (x < serie.xaxis.min || x > serie.xaxis.max) continue; - - distanceX = Math.abs(x - mouseX); - distanceY = Math.abs(y - mouseY); - - // Skip square root for speed - distance = distanceX * distanceX + distanceY * distanceY; - - if (distance < compare) { - compare = distance; - setClosest(closest); - } - - if (distanceX < compareX) { - compareX = distanceX; - setClosest(closestX); - } - } - } - - return check ? { - point : closest, - x : closestX - } : false; - }, - - drawMouseTrack : function (n) { - - var - pos = '', - s = n.series, - p = n.mouse.position, - m = n.mouse.margin, - elStyle = S_MOUSETRACK, - mouseTrack = this.mouseTrack, - plotOffset = this.plotOffset, - left = plotOffset.left, - right = plotOffset.right, - bottom = plotOffset.bottom, - top = plotOffset.top, - decimals = n.mouse.trackDecimals, - options = this.options; - - // Create - if (!mouseTrack) { - mouseTrack = D.node('
    '); - this.mouseTrack = mouseTrack; - D.insert(this.el, mouseTrack); - } - - if (!n.mouse.relative) { // absolute to the canvas - - if (p.charAt(0) == 'n') pos += 'top:' + (m + top) + 'px;bottom:auto;'; - else if (p.charAt(0) == 's') pos += 'bottom:' + (m + bottom) + 'px;top:auto;'; - if (p.charAt(1) == 'e') pos += 'right:' + (m + right) + 'px;left:auto;'; - else if (p.charAt(1) == 'w') pos += 'left:' + (m + left) + 'px;right:auto;'; - - // Bars - } else if (s.bars.show) { - pos += 'bottom:' + (m - top - n.yaxis.d2p(n.y/2) + this.canvasHeight) + 'px;top:auto;'; - pos += 'left:' + (m + left + n.xaxis.d2p(n.x - options.bars.barWidth/2)) + 'px;right:auto;'; - - // Pie - } else if (s.pie.show) { - var center = { - x: (this.plotWidth)/2, - y: (this.plotHeight)/2 - }, - radius = (Math.min(this.canvasWidth, this.canvasHeight) * s.pie.sizeRatio) / 2, - bisection = n.sAngle one of null, 'x', 'y' or 'xy' - color: '#B6D9FF', // => selection box color - fps: 20 // => frames-per-second - }, - - callbacks: { - 'flotr:mouseup' : function (event) { - - var - options = this.options.selection, - selection = this.selection, - pointer = this.getEventPosition(event); - - if (!options || !options.mode) return; - if (selection.interval) clearInterval(selection.interval); - - if (this.multitouches) { - selection.updateSelection(); - } else - if (!options.pinchOnly) { - selection.setSelectionPos(selection.selection.second, pointer); - } - selection.clearSelection(); - - if(selection.selecting && selection.selectionIsSane()){ - selection.drawSelection(); - selection.fireSelectEvent(); - this.ignoreClick = true; - } - }, - 'flotr:mousedown' : function (event) { - - var - options = this.options.selection, - selection = this.selection, - pointer = this.getEventPosition(event); - - if (!options || !options.mode) return; - if (!options.mode || (!isLeftClick(event) && _.isUndefined(event.touches))) return; - if (!options.pinchOnly) selection.setSelectionPos(selection.selection.first, pointer); - if (selection.interval) clearInterval(selection.interval); - - this.lastMousePos.pageX = null; - selection.selecting = false; - selection.interval = setInterval( - _.bind(selection.updateSelection, this), - 1000 / options.fps - ); - }, - 'flotr:destroy' : function (event) { - clearInterval(this.selection.interval); - } - }, - - // TODO This isn't used. Maybe it belongs in the draw area and fire select event methods? - getArea: function() { - - var s = this.selection.selection, - first = s.first, - second = s.second; - - return { - x1: Math.min(first.x, second.x), - x2: Math.max(first.x, second.x), - y1: Math.min(first.y, second.y), - y2: Math.max(first.y, second.y) - }; - }, - - selection: {first: {x: -1, y: -1}, second: {x: -1, y: -1}}, - prevSelection: null, - interval: null, - - /** - * Fires the 'flotr:select' event when the user made a selection. - */ - fireSelectEvent: function(name){ - var a = this.axes, - s = this.selection.selection, - x1, x2, y1, y2; - - name = name || 'select'; - - x1 = a.x.p2d(s.first.x); - x2 = a.x.p2d(s.second.x); - y1 = a.y.p2d(s.first.y); - y2 = a.y.p2d(s.second.y); - - E.fire(this.el, 'flotr:'+name, [{ - x1:Math.min(x1, x2), - y1:Math.min(y1, y2), - x2:Math.max(x1, x2), - y2:Math.max(y1, y2), - xfirst:x1, xsecond:x2, yfirst:y1, ysecond:y2 - }, this]); - }, - - /** - * Allows the user the manually select an area. - * @param {Object} area - Object with coordinates to select. - */ - setSelection: function(area, preventEvent){ - var options = this.options, - xa = this.axes.x, - ya = this.axes.y, - vertScale = ya.scale, - hozScale = xa.scale, - selX = options.selection.mode.indexOf('x') != -1, - selY = options.selection.mode.indexOf('y') != -1, - s = this.selection.selection; - - this.selection.clearSelection(); - - s.first.y = boundY((selX && !selY) ? 0 : (ya.max - area.y1) * vertScale, this); - s.second.y = boundY((selX && !selY) ? this.plotHeight - 1: (ya.max - area.y2) * vertScale, this); - s.first.x = boundX((selY && !selX) ? 0 : area.x1, this); - s.second.x = boundX((selY && !selX) ? this.plotWidth : area.x2, this); - - this.selection.drawSelection(); - if (!preventEvent) - this.selection.fireSelectEvent(); - }, - - /** - * Calculates the position of the selection. - * @param {Object} pos - Position object. - * @param {Event} event - Event object. - */ - setSelectionPos: function(pos, pointer) { - var mode = this.options.selection.mode, - selection = this.selection.selection; - - if(mode.indexOf('x') == -1) { - pos.x = (pos == selection.first) ? 0 : this.plotWidth; - }else{ - pos.x = boundX(pointer.relX, this); - } - - if (mode.indexOf('y') == -1) { - pos.y = (pos == selection.first) ? 0 : this.plotHeight - 1; - }else{ - pos.y = boundY(pointer.relY, this); - } - }, - /** - * Draws the selection box. - */ - drawSelection: function() { - - this.selection.fireSelectEvent('selecting'); - - var s = this.selection.selection, - octx = this.octx, - options = this.options, - plotOffset = this.plotOffset, - prevSelection = this.selection.prevSelection; - - if (prevSelection && - s.first.x == prevSelection.first.x && - s.first.y == prevSelection.first.y && - s.second.x == prevSelection.second.x && - s.second.y == prevSelection.second.y) { - return; - } - - octx.save(); - octx.strokeStyle = this.processColor(options.selection.color, {opacity: 0.8}); - octx.lineWidth = 1; - octx.lineJoin = 'miter'; - octx.fillStyle = this.processColor(options.selection.color, {opacity: 0.4}); - - this.selection.prevSelection = { - first: { x: s.first.x, y: s.first.y }, - second: { x: s.second.x, y: s.second.y } - }; - - var x = Math.min(s.first.x, s.second.x), - y = Math.min(s.first.y, s.second.y), - w = Math.abs(s.second.x - s.first.x), - h = Math.abs(s.second.y - s.first.y); - - octx.fillRect(x + plotOffset.left+0.5, y + plotOffset.top+0.5, w, h); - octx.strokeRect(x + plotOffset.left+0.5, y + plotOffset.top+0.5, w, h); - octx.restore(); - }, - - /** - * Updates (draws) the selection box. - */ - updateSelection: function(){ - if (!this.lastMousePos.pageX) return; - - this.selection.selecting = true; - - if (this.multitouches) { - this.selection.setSelectionPos(this.selection.selection.first, this.getEventPosition(this.multitouches[0])); - this.selection.setSelectionPos(this.selection.selection.second, this.getEventPosition(this.multitouches[1])); - } else - if (this.options.selection.pinchOnly) { - return; - } else { - this.selection.setSelectionPos(this.selection.selection.second, this.lastMousePos); - } - - this.selection.clearSelection(); - - if(this.selection.selectionIsSane()) { - this.selection.drawSelection(); - } - }, - - /** - * Removes the selection box from the overlay canvas. - */ - clearSelection: function() { - if (!this.selection.prevSelection) return; - - var prevSelection = this.selection.prevSelection, - lw = 1, - plotOffset = this.plotOffset, - x = Math.min(prevSelection.first.x, prevSelection.second.x), - y = Math.min(prevSelection.first.y, prevSelection.second.y), - w = Math.abs(prevSelection.second.x - prevSelection.first.x), - h = Math.abs(prevSelection.second.y - prevSelection.first.y); - - this.octx.clearRect(x + plotOffset.left - lw + 0.5, - y + plotOffset.top - lw, - w + 2 * lw + 0.5, - h + 2 * lw + 0.5); - - this.selection.prevSelection = null; - }, - /** - * Determines whether or not the selection is sane and should be drawn. - * @return {Boolean} - True when sane, false otherwise. - */ - selectionIsSane: function(){ - var s = this.selection.selection; - return Math.abs(s.second.x - s.first.x) >= 5 || - Math.abs(s.second.y - s.first.y) >= 5; - } - -}); - -})(); - -(function () { - -var D = Flotr.DOM; - -Flotr.addPlugin('labels', { - - callbacks : { - 'flotr:afterdraw' : function () { - this.labels.draw(); - } - }, - - draw: function(){ - // Construct fixed width label boxes, which can be styled easily. - var - axis, tick, left, top, xBoxWidth, - radius, sides, coeff, angle, - div, i, html = '', - noLabels = 0, - options = this.options, - ctx = this.ctx, - a = this.axes, - style = { size: options.fontSize }; - - for (i = 0; i < a.x.ticks.length; ++i){ - if (a.x.ticks[i].label) { ++noLabels; } - } - xBoxWidth = this.plotWidth / noLabels; - - if (options.grid.circular) { - ctx.save(); - ctx.translate(this.plotOffset.left + this.plotWidth / 2, - this.plotOffset.top + this.plotHeight / 2); - - radius = this.plotHeight * options.radar.radiusRatio / 2 + options.fontSize; - sides = this.axes.x.ticks.length; - coeff = 2 * (Math.PI / sides); - angle = -Math.PI / 2; - - drawLabelCircular(this, a.x, false); - drawLabelCircular(this, a.x, true); - drawLabelCircular(this, a.y, false); - drawLabelCircular(this, a.y, true); - ctx.restore(); - } - - if (!options.HtmlText && this.textEnabled) { - drawLabelNoHtmlText(this, a.x, 'center', 'top'); - drawLabelNoHtmlText(this, a.x2, 'center', 'bottom'); - drawLabelNoHtmlText(this, a.y, 'right', 'middle'); - drawLabelNoHtmlText(this, a.y2, 'left', 'middle'); - - } else if (( - a.x.options.showLabels || - a.x2.options.showLabels || - a.y.options.showLabels || - a.y2.options.showLabels) && - !options.grid.circular - ) { - - html = ''; - - drawLabelHtml(this, a.x); - drawLabelHtml(this, a.x2); - drawLabelHtml(this, a.y); - drawLabelHtml(this, a.y2); - - ctx.stroke(); - ctx.restore(); - div = D.create('div'); - D.setStyles(div, { - fontSize: 'smaller', - color: options.grid.color - }); - div.className = 'flotr-labels'; - D.insert(this.el, div); - D.insert(div, html); - } - - function drawLabelCircular (graph, axis, minorTicks) { - var - ticks = minorTicks ? axis.minorTicks : axis.ticks, - isX = axis.orientation === 1, - isFirst = axis.n === 1, - style, offset; - - style = { - color : axis.options.color || options.grid.color, - angle : Flotr.toRad(axis.options.labelsAngle), - textBaseline : 'middle' - }; - - for (i = 0; i < ticks.length && - (minorTicks ? axis.options.showMinorLabels : axis.options.showLabels); ++i){ - tick = ticks[i]; - tick.label += ''; - if (!tick.label || !tick.label.length) { continue; } - - x = Math.cos(i * coeff + angle) * radius; - y = Math.sin(i * coeff + angle) * radius; - - style.textAlign = isX ? (Math.abs(x) < 0.1 ? 'center' : (x < 0 ? 'right' : 'left')) : 'left'; - - Flotr.drawText( - ctx, tick.label, - isX ? x : 3, - isX ? y : -(axis.ticks[i].v / axis.max) * (radius - options.fontSize), - style - ); - } - } - - function drawLabelNoHtmlText (graph, axis, textAlign, textBaseline) { - var - isX = axis.orientation === 1, - isFirst = axis.n === 1, - style, offset; - - style = { - color : axis.options.color || options.grid.color, - textAlign : textAlign, - textBaseline : textBaseline, - angle : Flotr.toRad(axis.options.labelsAngle) - }; - style = Flotr.getBestTextAlign(style.angle, style); - - for (i = 0; i < axis.ticks.length && continueShowingLabels(axis); ++i) { - - tick = axis.ticks[i]; - if (!tick.label || !tick.label.length) { continue; } - - offset = axis.d2p(tick.v); - if (offset < 0 || - offset > (isX ? graph.plotWidth : graph.plotHeight)) { continue; } - - Flotr.drawText( - ctx, tick.label, - leftOffset(graph, isX, isFirst, offset), - topOffset(graph, isX, isFirst, offset), - style - ); - - // Only draw on axis y2 - if (!isX && !isFirst) { - ctx.save(); - ctx.strokeStyle = style.color; - ctx.beginPath(); - ctx.moveTo(graph.plotOffset.left + graph.plotWidth - 8, graph.plotOffset.top + axis.d2p(tick.v)); - ctx.lineTo(graph.plotOffset.left + graph.plotWidth, graph.plotOffset.top + axis.d2p(tick.v)); - ctx.stroke(); - ctx.restore(); - } - } - - function continueShowingLabels (axis) { - return axis.options.showLabels && axis.used; - } - function leftOffset (graph, isX, isFirst, offset) { - return graph.plotOffset.left + - (isX ? offset : - (isFirst ? - -options.grid.labelMargin : - options.grid.labelMargin + graph.plotWidth)); - } - function topOffset (graph, isX, isFirst, offset) { - return graph.plotOffset.top + - (isX ? options.grid.labelMargin : offset) + - ((isX && isFirst) ? graph.plotHeight : 0); - } - } - - function drawLabelHtml (graph, axis) { - var - isX = axis.orientation === 1, - isFirst = axis.n === 1, - name = '', - left, style, top, - offset = graph.plotOffset; - - if (!isX && !isFirst) { - ctx.save(); - ctx.strokeStyle = axis.options.color || options.grid.color; - ctx.beginPath(); - } - - if (axis.options.showLabels && (isFirst ? true : axis.used)) { - for (i = 0; i < axis.ticks.length; ++i) { - tick = axis.ticks[i]; - if (!tick.label || !tick.label.length || - ((isX ? offset.left : offset.top) + axis.d2p(tick.v) < 0) || - ((isX ? offset.left : offset.top) + axis.d2p(tick.v) > (isX ? graph.canvasWidth : graph.canvasHeight))) { - continue; - } - top = offset.top + - (isX ? - ((isFirst ? 1 : -1 ) * (graph.plotHeight + options.grid.labelMargin)) : - axis.d2p(tick.v) - axis.maxLabel.height / 2); - left = isX ? (offset.left + axis.d2p(tick.v) - xBoxWidth / 2) : 0; - - name = ''; - if (i === 0) { - name = ' first'; - } else if (i === axis.ticks.length - 1) { - name = ' last'; - } - name += isX ? ' flotr-grid-label-x' : ' flotr-grid-label-y'; - - html += [ - '
    ' + tick.label + '
    ' - ].join(' '); - - if (!isX && !isFirst) { - ctx.moveTo(offset.left + graph.plotWidth - 8, offset.top + axis.d2p(tick.v)); - ctx.lineTo(offset.left + graph.plotWidth, offset.top + axis.d2p(tick.v)); - } - } - } - } - } - -}); -})(); - -(function () { - -var - D = Flotr.DOM, - _ = Flotr._; - -Flotr.addPlugin('legend', { - options: { - show: true, // => setting to true will show the legend, hide otherwise - noColumns: 1, // => number of colums in legend table // @todo: doesn't work for HtmlText = false - labelFormatter: function(v){return v;}, // => fn: string -> string - labelBoxBorderColor: '#CCCCCC', // => border color for the little label boxes - labelBoxWidth: 14, - labelBoxHeight: 10, - labelBoxMargin: 5, - labelBoxOpacity: 0.4, - container: null, // => container (as jQuery object) to put legend in, null means default on top of graph - position: 'nw', // => position of default legend container within plot - margin: 5, // => distance from grid edge to default legend container within plot - backgroundColor: null, // => null means auto-detect - backgroundOpacity: 0.85// => set to 0 to avoid background, set to 1 for a solid background - }, - callbacks: { - 'flotr:afterinit': function() { - this.legend.insertLegend(); - } - }, - /** - * Adds a legend div to the canvas container or draws it on the canvas. - */ - insertLegend: function(){ - - if(!this.options.legend.show) - return; - - var series = this.series, - plotOffset = this.plotOffset, - options = this.options, - legend = options.legend, - fragments = [], - rowStarted = false, - ctx = this.ctx, - itemCount = _.filter(series, function(s) {return (s.label && !s.hide);}).length, - p = legend.position, - m = legend.margin, - i, label, color; - - if (itemCount) { - if (!options.HtmlText && this.textEnabled && !legend.container) { - var style = { - size: options.fontSize*1.1, - color: options.grid.color - }; - - var lbw = legend.labelBoxWidth, - lbh = legend.labelBoxHeight, - lbm = legend.labelBoxMargin, - offsetX = plotOffset.left + m, - offsetY = plotOffset.top + m; - - // We calculate the labels' max width - var labelMaxWidth = 0; - for(i = series.length - 1; i > -1; --i){ - if(!series[i].label || series[i].hide) continue; - label = legend.labelFormatter(series[i].label); - labelMaxWidth = Math.max(labelMaxWidth, this._text.measureText(label, style).width); - } - - var legendWidth = Math.round(lbw + lbm*3 + labelMaxWidth), - legendHeight = Math.round(itemCount*(lbm+lbh) + lbm); - - if(p.charAt(0) == 's') offsetY = plotOffset.top + this.plotHeight - (m + legendHeight); - if(p.charAt(1) == 'e') offsetX = plotOffset.left + this.plotWidth - (m + legendWidth); - - // Legend box - color = this.processColor(legend.backgroundColor || 'rgb(240,240,240)', {opacity: legend.backgroundOpacity || 0.1}); - - ctx.fillStyle = color; - ctx.fillRect(offsetX, offsetY, legendWidth, legendHeight); - ctx.strokeStyle = legend.labelBoxBorderColor; - ctx.strokeRect(Flotr.toPixel(offsetX), Flotr.toPixel(offsetY), legendWidth, legendHeight); - - // Legend labels - var x = offsetX + lbm; - var y = offsetY + lbm; - for(i = 0; i < series.length; i++){ - if(!series[i].label || series[i].hide) continue; - label = legend.labelFormatter(series[i].label); - - ctx.fillStyle = series[i].color; - ctx.fillRect(x, y, lbw-1, lbh-1); - - ctx.strokeStyle = legend.labelBoxBorderColor; - ctx.lineWidth = 1; - ctx.strokeRect(Math.ceil(x)-1.5, Math.ceil(y)-1.5, lbw+2, lbh+2); - - // Legend text - Flotr.drawText(ctx, label, x + lbw + lbm, y + lbh, style); - - y += lbh + lbm; - } - } - else { - for(i = 0; i < series.length; ++i){ - if(!series[i].label || series[i].hide) continue; - - if(i % legend.noColumns === 0){ - fragments.push(rowStarted ? '' : ''); - rowStarted = true; - } - - // @TODO remove requirement on bars - var s = series[i], - boxWidth = legend.labelBoxWidth, - boxHeight = legend.labelBoxHeight, - opacityValue = (s.bars ? s.bars.fillOpacity : legend.labelBoxOpacity), - opacity = 'opacity:' + opacityValue + ';filter:alpha(opacity=' + opacityValue*100 + ');'; - - label = legend.labelFormatter(s.label); - color = 'background-color:' + ((s.bars && s.bars.show && s.bars.fillColor && s.bars.fill) ? s.bars.fillColor : s.color) + ';'; - - fragments.push( - '', - '
    ', - '
    ', // Border - '
    ', // Background - '
    ', - '
    ', - '', - '', label, '' - ); - } - if(rowStarted) fragments.push(''); - - if(fragments.length > 0){ - var table = '' + fragments.join('') + '
    '; - if(legend.container){ - D.insert(legend.container, table); - } - else { - var styles = {position: 'absolute', 'z-index': 2}; - - if(p.charAt(0) == 'n') { styles.top = (m + plotOffset.top) + 'px'; styles.bottom = 'auto'; } - else if(p.charAt(0) == 's') { styles.bottom = (m + plotOffset.bottom) + 'px'; styles.top = 'auto'; } - if(p.charAt(1) == 'e') { styles.right = (m + plotOffset.right) + 'px'; styles.left = 'auto'; } - else if(p.charAt(1) == 'w') { styles.left = (m + plotOffset.left) + 'px'; styles.right = 'auto'; } - - var div = D.create('div'), size; - div.className = 'flotr-legend'; - D.setStyles(div, styles); - D.insert(div, table); - D.insert(this.el, div); - - if(!legend.backgroundOpacity) - return; - - var c = legend.backgroundColor || options.grid.backgroundColor || '#ffffff'; - - _.extend(styles, D.size(div), { - 'backgroundColor': c, - 'z-index': 1 - }); - styles.width += 'px'; - styles.height += 'px'; - - // Put in the transparent background separately to avoid blended labels and - div = D.create('div'); - div.className = 'flotr-legend-bg'; - D.setStyles(div, styles); - D.opacity(div, legend.backgroundOpacity); - D.insert(div, ' '); - D.insert(this.el, div); - } - } - } - } - } -}); -})(); - -/** Spreadsheet **/ -(function() { - -function getRowLabel(value){ - if (this.options.spreadsheet.tickFormatter){ - //TODO maybe pass the xaxis formatter to the custom tick formatter as an opt-out? - return this.options.spreadsheet.tickFormatter(value); - } - else { - var t = _.find(this.axes.x.ticks, function(t){return t.v == value;}); - if (t) { - return t.label; - } - return value; - } -} - -var - D = Flotr.DOM, - _ = Flotr._; - -Flotr.addPlugin('spreadsheet', { - options: { - show: false, // => show the data grid using two tabs - tabGraphLabel: 'Graph', - tabDataLabel: 'Data', - toolbarDownload: 'Download CSV', // @todo: add better language support - toolbarSelectAll: 'Select all', - csvFileSeparator: ',', - decimalSeparator: '.', - tickFormatter: null, - initialTab: 'graph' - }, - /** - * Builds the tabs in the DOM - */ - callbacks: { - 'flotr:afterconstruct': function(){ - // @TODO necessary? - //this.el.select('.flotr-tabs-group,.flotr-datagrid-container').invoke('remove'); - - if (!this.options.spreadsheet.show) return; - - var ss = this.spreadsheet, - container = D.node('
    '), - graph = D.node('
    '+this.options.spreadsheet.tabGraphLabel+'
    '), - data = D.node('
    '+this.options.spreadsheet.tabDataLabel+'
    '), - offset; - - ss.tabsContainer = container; - ss.tabs = { graph : graph, data : data }; - - D.insert(container, graph); - D.insert(container, data); - D.insert(this.el, container); - - offset = D.size(data).height + 2; - this.plotOffset.bottom += offset; - - D.setStyles(container, {top: this.canvasHeight-offset+'px'}); - - this. - observe(graph, 'click', function(){ss.showTab('graph');}). - observe(data, 'click', function(){ss.showTab('data');}); - if (this.options.spreadsheet.initialTab !== 'graph'){ - ss.showTab(this.options.spreadsheet.initialTab); - } - } - }, - /** - * Builds a matrix of the data to make the correspondance between the x values and the y values : - * X value => Y values from the axes - * @return {Array} The data grid - */ - loadDataGrid: function(){ - if (this.seriesData) return this.seriesData; - - var s = this.series, - rows = {}; - - /* The data grid is a 2 dimensions array. There is a row for each X value. - * Each row contains the x value and the corresponding y value for each serie ('undefined' if there isn't one) - **/ - _.each(s, function(serie, i){ - _.each(serie.data, function (v) { - var x = v[0], - y = v[1], - r = rows[x]; - if (r) { - r[i+1] = y; - } else { - var newRow = []; - newRow[0] = x; - newRow[i+1] = y; - rows[x] = newRow; - } - }); - }); - - // The data grid is sorted by x value - this.seriesData = _.sortBy(rows, function(row, x){ - return parseInt(x, 10); - }); - return this.seriesData; - }, - /** - * Constructs the data table for the spreadsheet - * @todo make a spreadsheet manager (Flotr.Spreadsheet) - * @return {Element} The resulting table element - */ - constructDataGrid: function(){ - // If the data grid has already been built, nothing to do here - if (this.spreadsheet.datagrid) return this.spreadsheet.datagrid; - - var s = this.series, - datagrid = this.spreadsheet.loadDataGrid(), - colgroup = [''], - buttonDownload, buttonSelect, t; - - // First row : series' labels - var html = ['']; - html.push(''); - _.each(s, function(serie,i){ - html.push(''); - colgroup.push(''); - }); - html.push(''); - // Data rows - _.each(datagrid, function(row){ - html.push(''); - _.times(s.length+1, function(i){ - var tag = 'td', - value = row[i], - // TODO: do we really want to handle problems with floating point - // precision here? - content = (!_.isUndefined(value) ? Math.round(value*100000)/100000 : ''); - if (i === 0) { - tag = 'th'; - var label = getRowLabel.call(this, content); - if (label) content = label; - } - - html.push('<'+tag+(tag=='th'?' scope="row"':'')+'>'+content+''); - }, this); - html.push(''); - }, this); - colgroup.push(''); - t = D.node(html.join('')); - - /** - * @TODO disabled this - if (!Flotr.isIE || Flotr.isIE == 9) { - function handleMouseout(){ - t.select('colgroup col.hover, th.hover').invoke('removeClassName', 'hover'); - } - function handleMouseover(e){ - var td = e.element(), - siblings = td.previousSiblings(); - t.select('th[scope=col]')[siblings.length-1].addClassName('hover'); - t.select('colgroup col')[siblings.length].addClassName('hover'); - } - _.each(t.select('td'), function(td) { - Flotr.EventAdapter. - observe(td, 'mouseover', handleMouseover). - observe(td, 'mouseout', handleMouseout); - }); - } - */ - - buttonDownload = D.node( - ''); - - buttonSelect = D.node( - ''); - - this. - observe(buttonDownload, 'click', _.bind(this.spreadsheet.downloadCSV, this)). - observe(buttonSelect, 'click', _.bind(this.spreadsheet.selectAllData, this)); - - var toolbar = D.node('
    '); - D.insert(toolbar, buttonDownload); - D.insert(toolbar, buttonSelect); - - var containerHeight =this.canvasHeight - D.size(this.spreadsheet.tabsContainer).height-2, - container = D.node('
    '); - - D.insert(container, toolbar); - D.insert(container, t); - D.insert(this.el, container); - this.spreadsheet.datagrid = t; - this.spreadsheet.container = container; - - return t; - }, - /** - * Shows the specified tab, by its name - * @todo make a tab manager (Flotr.Tabs) - * @param {String} tabName - The tab name - */ - showTab: function(tabName){ - if (this.spreadsheet.activeTab === tabName){ - return; - } - switch(tabName) { - case 'graph': - D.hide(this.spreadsheet.container); - D.removeClass(this.spreadsheet.tabs.data, 'selected'); - D.addClass(this.spreadsheet.tabs.graph, 'selected'); - break; - case 'data': - if (!this.spreadsheet.datagrid) - this.spreadsheet.constructDataGrid(); - D.show(this.spreadsheet.container); - D.addClass(this.spreadsheet.tabs.data, 'selected'); - D.removeClass(this.spreadsheet.tabs.graph, 'selected'); - break; - default: - throw 'Illegal tab name: ' + tabName; - } - this.spreadsheet.activeTab = tabName; - }, - /** - * Selects the data table in the DOM for copy/paste - */ - selectAllData: function(){ - if (this.spreadsheet.tabs) { - var selection, range, doc, win, node = this.spreadsheet.constructDataGrid(); - - this.spreadsheet.showTab('data'); - - // deferred to be able to select the table - setTimeout(function () { - if ((doc = node.ownerDocument) && (win = doc.defaultView) && - win.getSelection && doc.createRange && - (selection = window.getSelection()) && - selection.removeAllRanges) { - range = doc.createRange(); - range.selectNode(node); - selection.removeAllRanges(); - selection.addRange(range); - } - else if (document.body && document.body.createTextRange && - (range = document.body.createTextRange())) { - range.moveToElementText(node); - range.select(); - } - }, 0); - return true; - } - else return false; - }, - /** - * Converts the data into CSV in order to download a file - */ - downloadCSV: function(){ - var csv = '', - series = this.series, - options = this.options, - dg = this.spreadsheet.loadDataGrid(), - separator = encodeURIComponent(options.spreadsheet.csvFileSeparator); - - if (options.spreadsheet.decimalSeparator === options.spreadsheet.csvFileSeparator) { - throw "The decimal separator is the same as the column separator ("+options.spreadsheet.decimalSeparator+")"; - } - - // The first row - _.each(series, function(serie, i){ - csv += separator+'"'+(serie.label || String.fromCharCode(65+i)).replace(/\"/g, '\\"')+'"'; - }); - - csv += "%0D%0A"; // \r\n - - // For each row - csv += _.reduce(dg, function(memo, row){ - var rowLabel = getRowLabel.call(this, row[0]) || ''; - rowLabel = '"'+(rowLabel+'').replace(/\"/g, '\\"')+'"'; - var numbers = row.slice(1).join(separator); - if (options.spreadsheet.decimalSeparator !== '.') { - numbers = numbers.replace(/\./g, options.spreadsheet.decimalSeparator); - } - return memo + rowLabel+separator+numbers+"%0D%0A"; // \t and \r\n - }, '', this); - - if (Flotr.isIE && Flotr.isIE < 9) { - csv = csv.replace(new RegExp(separator, 'g'), decodeURIComponent(separator)).replace(/%0A/g, '\n').replace(/%0D/g, '\r'); - window.open().document.write(csv); - } - else window.open('data:text/csv,'+csv); - } -}); -})(); - -(function () { - -var D = Flotr.DOM; - -Flotr.addPlugin('titles', { - callbacks: { - 'flotr:afterdraw': function() { - this.titles.drawTitles(); - } - }, - /** - * Draws the title and the subtitle - */ - drawTitles : function () { - var html, - options = this.options, - margin = options.grid.labelMargin, - ctx = this.ctx, - a = this.axes; - - if (!options.HtmlText && this.textEnabled) { - var style = { - size: options.fontSize, - color: options.grid.color, - textAlign: 'center' - }; - - // Add subtitle - if (options.subtitle){ - Flotr.drawText( - ctx, options.subtitle, - this.plotOffset.left + this.plotWidth/2, - this.titleHeight + this.subtitleHeight - 2, - style - ); - } - - style.weight = 1.5; - style.size *= 1.5; - - // Add title - if (options.title){ - Flotr.drawText( - ctx, options.title, - this.plotOffset.left + this.plotWidth/2, - this.titleHeight - 2, - style - ); - } - - style.weight = 1.8; - style.size *= 0.8; - - // Add x axis title - if (a.x.options.title && a.x.used){ - style.textAlign = a.x.options.titleAlign || 'center'; - style.textBaseline = 'top'; - style.angle = Flotr.toRad(a.x.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.x.options.title, - this.plotOffset.left + this.plotWidth/2, - this.plotOffset.top + a.x.maxLabel.height + this.plotHeight + 2 * margin, - style - ); - } - - // Add x2 axis title - if (a.x2.options.title && a.x2.used){ - style.textAlign = a.x2.options.titleAlign || 'center'; - style.textBaseline = 'bottom'; - style.angle = Flotr.toRad(a.x2.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.x2.options.title, - this.plotOffset.left + this.plotWidth/2, - this.plotOffset.top - a.x2.maxLabel.height - 2 * margin, - style - ); - } - - // Add y axis title - if (a.y.options.title && a.y.used){ - style.textAlign = a.y.options.titleAlign || 'right'; - style.textBaseline = 'middle'; - style.angle = Flotr.toRad(a.y.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.y.options.title, - this.plotOffset.left - a.y.maxLabel.width - 2 * margin, - this.plotOffset.top + this.plotHeight / 2, - style - ); - } - - // Add y2 axis title - if (a.y2.options.title && a.y2.used){ - style.textAlign = a.y2.options.titleAlign || 'left'; - style.textBaseline = 'middle'; - style.angle = Flotr.toRad(a.y2.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.y2.options.title, - this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin, - this.plotOffset.top + this.plotHeight / 2, - style - ); - } - } - else { - html = []; - - // Add title - if (options.title) - html.push( - '
    ', options.title, '
    ' - ); - - // Add subtitle - if (options.subtitle) - html.push( - '
    ', options.subtitle, '
    ' - ); - - html.push(''); - - html.push('
    '); - - // Add x axis title - if (a.x.options.title && a.x.used) - html.push( - '
    ', a.x.options.title, '
    ' - ); - - // Add x2 axis title - if (a.x2.options.title && a.x2.used) - html.push( - '
    ', a.x2.options.title, '
    ' - ); - - // Add y axis title - if (a.y.options.title && a.y.used) - html.push( - '
    ', a.y.options.title, '
    ' - ); - - // Add y2 axis title - if (a.y2.options.title && a.y2.used) - html.push( - '
    ', a.y2.options.title, '
    ' - ); - - html = html.join(''); - - var div = D.create('div'); - D.setStyles({ - color: options.grid.color - }); - div.className = 'flotr-titles'; - D.insert(this.el, div); - D.insert(div, html); - } - } -}); -})(); diff --git a/addons/web_graph/static/lib/flotr2/flotr2.min.js b/addons/web_graph/static/lib/flotr2/flotr2.min.js deleted file mode 100644 index 0dce3034464..00000000000 --- a/addons/web_graph/static/lib/flotr2/flotr2.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * bean.js - copyright Jacob Thornton 2011 - * https://github.com/fat/bean - * MIT License - * special thanks to: - * dean edwards: http://dean.edwards.name/ - * dperini: https://github.com/dperini/nwevents - * the entire mootools team: github.com/mootools/mootools-core - *//*global module:true, define:true*/ -!function(a,b,c){typeof module!="undefined"?module.exports=c(a,b):typeof define=="function"&&typeof define.amd=="object"?define(c):b[a]=c(a,b)}("bean",this,function(a,b){var c=window,d=b[a],e=/over|out/,f=/[^\.]*(?=\..*)\.|.*/,g=/\..*/,h="addEventListener",i="attachEvent",j="removeEventListener",k="detachEvent",l=document||{},m=l.documentElement||{},n=m[h],o=n?h:i,p=Array.prototype.slice,q=/click|mouse|menu|drag|drop/i,r=/^touch|^gesture/i,s={one:1},t=function(a,b,c){for(c=0;c0){b=b.split(" ");for(j=b.length;j--;)G(a,b[j],c);return a}h=l&&b.replace(g,""),h&&u[h]&&(h=u[h].type);if(!b||l){if(i=l&&b.replace(f,""))i=i.split(".");k(a,h,c,i)}else if(typeof b=="function")k(a,null,b);else for(d in b)b.hasOwnProperty(d)&&G(a,d,b[d]);return a},H=function(a,b,c,d,e){var f,g,h,i,j=c,k=c&&typeof c=="string";if(b&&!c&&typeof b=="object")for(f in b)b.hasOwnProperty(f)&&H.apply(this,[a,f,b[f]]);else{i=arguments.length>3?p.call(arguments,3):[],g=(k?c:b).split(" "),k&&(c=F(b,j=d,e))&&(i=p.call(i,1)),this===s&&(c=C(G,a,b,c,j));for(h=g.length;h--;)E(a,g[h],c,j,i)}return a},I=function(){return H.apply(s,arguments)},J=n?function(a,b,d){var e=l.createEvent(a?"HTMLEvents":"UIEvents");e[a?"initEvent":"initUIEvent"](b,!0,!0,c,1),d.dispatchEvent(e)}:function(a,b,c){c=w(c,a),a?c.fireEvent("on"+b,l.createEventObject()):c["_on"+b]++},K=function(a,b,c){var d,e,h,i,j,k=b.split(" ");for(d=k.length;d--;){b=k[d].replace(g,"");if(i=k[d].replace(f,""))i=i.split(".");if(!i&&!c&&a[o])J(t[b],b,a);else{j=y.get(a,b),c=[!1].concat(c);for(e=0,h=j.length;e=d.computed&&(d={value:a,computed:g})}),d.value},w.min=function(a,b,c){if(!b&&w.isArray(a))return Math.min.apply(Math,a);var d={computed:Infinity};return x(a,function(a,e,f){var g=b?b.call(c,a,e,f):a;gd?1:0}),"value")},w.groupBy=function(a,b){var c={};return x(a,function(a,d){var e=b(a,d);(c[e]||(c[e]=[])).push(a)}),c},w.sortedIndex=function(a,b,c){c||(c=w.identity);var d=0,e=a.length;while(d>1;c(a[f])=0})})},w.difference=function(a,b){return w.filter(a,function(a){return!w.include(b,a)})},w.zip=function(){var a=g.call(arguments),b=w.max(w.pluck(a,"length")),c=new Array(b);for(var d=0;d=0;c--)b=[a[c].apply(this,b)];return b[0]}},w.after=function(a,b){return function(){if(--a<1)return b.apply(this,arguments)}},w.keys=u||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[];for(var c in a)j.call(a,c)&&(b[b.length]=c);return b},w.values=function(a){return w.map(a,w.identity)},w.functions=w.methods=function(a){var b=[];for(var c in a)w.isFunction(a[c])&&b.push(c);return b.sort()},w.extend=function(a){return x(g.call(arguments,1),function(b){for(var c in b)b[c]!==void 0&&(a[c]=b[c])}),a},w.defaults=function(a){return x(g.call(arguments,1),function(b){for(var c in b)a[c]==null&&(a[c]=b[c])}),a},w.clone=function(a){return w.isArray(a)?a.slice():w.extend({},a)},w.tap=function(a,b){return b(a),a},w.isEqual=function(a,b){if(a===b)return!0;var c=typeof a,d=typeof b;if(c!=d)return!1;if(a==b)return!0;if(!a&&b||a&&!b)return!1;a._chain&&(a=a._wrapped),b._chain&&(b=b._wrapped);if(a.isEqual)return a.isEqual(b);if(b.isEqual)return b.isEqual(a);if(w.isDate(a)&&w.isDate(b))return a.getTime()===b.getTime();if(w.isNaN(a)&&w.isNaN(b))return!1;if(w.isRegExp(a)&&w.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(c!=="object")return!1;if(a.length&&a.length!==b.length)return!1;var e=w.keys(a),f=w.keys(b);if(e.length!=f.length)return!1;for(var g in a)if(!(g in b)||!w.isEqual(a[g],b[g]))return!1;return!0},w.isEmpty=function(a){if(w.isArray(a)||w.isString(a))return a.length===0;for(var b in a)if(j.call(a,b))return!1;return!0},w.isElement=function(a){return!!a&&a.nodeType==1},w.isArray=t||function(a){return i.call(a)==="[object Array]"},w.isObject=function(a){return a===Object(a)},w.isArguments=function(a){return!!a&&!!j.call(a,"callee")},w.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)},w.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)},w.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)},w.isNaN=function(a){return a!==a},w.isBoolean=function(a){return a===!0||a===!1},w.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)},w.isRegExp=function(a){return!(!(a&&a.test&&a.exec)||!a.ignoreCase&&a.ignoreCase!==!1)},w.isNull=function(a){return a===null},w.isUndefined=function(a){return a===void 0},w.noConflict=function(){return a._=b,this},w.identity=function(a){return a},w.times=function(a,b,c){for(var d=0;d/g,interpolate:/<%=([\s\S]+?)%>/g},w.template=function(a,b){var c=w.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(c.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(c.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj",d);return b?e(b):e};var B=function(a){this._wrapped=a};w.prototype=B.prototype;var C=function(a,b){return b?w(a).chain():a},D=function(a,b){B.prototype[a]=function(){var a=g.call(arguments);return h.call(a,this._wrapped),C(b.apply(w,a),this._chain)}};w.mixin(w),x(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=d[a];B.prototype[a]=function(){return b.apply(this._wrapped,arguments),C(this._wrapped,this._chain)}}),x(["concat","join","slice"],function(a){var b=d[a];B.prototype[a]=function(){return C(b.apply(this._wrapped,arguments),this._chain)}}),B.prototype.chain=function(){return this._chain=!0,this},B.prototype.value=function(){return this._wrapped}})(); -/** - * Flotr2 (c) 2012 Carl Sutherland - * MIT License - * Special thanks to: - * Flotr: http://code.google.com/p/flotr/ (fork) - * Flot: https://github.com/flot/flot (original fork) - */ -(function(){var a=this,b=this.Flotr,c;c={_:_,bean:bean,isIphone:/iphone/i.test(navigator.userAgent),isIE:navigator.appVersion.indexOf("MSIE")!=-1?parseFloat(navigator.appVersion.split("MSIE")[1]):!1,graphTypes:{},plugins:{},addType:function(a,b){c.graphTypes[a]=b,c.defaultOptions[a]=b.options||{},c.defaultOptions.defaultType=c.defaultOptions.defaultType||a},addPlugin:function(a,b){c.plugins[a]=b,c.defaultOptions[a]=b.options||{}},draw:function(a,b,d,e){return e=e||c.Graph,new e(a,b,d)},merge:function(a,b){var d,e,f=b||{};for(d in a)e=a[d],e&&typeof e=="object"?e.constructor===Array?f[d]=this._.clone(e):e.constructor!==RegExp&&!this._.isElement(e)?f[d]=c.merge(e,b?b[d]:undefined):f[d]=e:f[d]=e;return f},clone:function(a){return c.merge(a,{})},getTickSize:function(a,b,d,e){var f=(d-b)/a,g=c.getMagnitude(f),h=10,i=f/g;return i<1.5?h=1:i<2.25?h=2:i<3?h=e===0?2:2.5:i<7.5&&(h=5),h*g},defaultTickFormatter:function(a,b){return a+""},defaultTrackFormatter:function(a){return"("+a.x+", "+a.y+")"},engineeringNotation:function(a,b,c){var d=["Y","Z","E","P","T","G","M","k",""],e=["y","z","a","f","p","n","µ","m",""],f=d.length;c=c||1e3,b=Math.pow(10,b||2);if(a===0)return 0;if(a>1)while(f--&&a>=c)a/=c;else{d=e,f=d.length;while(f--&&a<1)a*=c}return Math.round(a*b)/b+d[f]},getMagnitude:function(a){return Math.pow(10,Math.floor(Math.log(a)/Math.LN10))},toPixel:function(a){return Math.floor(a)+.5},toRad:function(a){return-a*(Math.PI/180)},floorInBase:function(a,b){return b*Math.floor(a/b)},drawText:function(a,b,d,e,f){if(!a.fillText){a.drawText(b,d,e,f);return}f=this._.extend({size:c.defaultOptions.fontSize,color:"#000000",textAlign:"left",textBaseline:"bottom",weight:1,angle:0},f),a.save(),a.translate(d,e),a.rotate(f.angle),a.fillStyle=f.color,a.font=(f.weight>1?"bold ":"")+f.size*1.3+"px sans-serif",a.textAlign=f.textAlign,a.textBaseline=f.textBaseline,a.fillText(b,0,0),a.restore()},getBestTextAlign:function(a,b){return b=b||{textAlign:"center",textBaseline:"middle"},a+=c.getTextAngleFromAlign(b),Math.abs(Math.cos(a))>.01&&(b.textAlign=Math.cos(a)>0?"right":"left"),Math.abs(Math.sin(a))>.01&&(b.textBaseline=Math.sin(a)>0?"top":"bottom"),b},alignTable:{"right middle":0,"right top":Math.PI/4,"center top":Math.PI/2,"left top":3*(Math.PI/4),"left middle":Math.PI,"left bottom":-3*(Math.PI/4),"center bottom":-Math.PI/2,"right bottom":-Math.PI/4,"center middle":0},getTextAngleFromAlign:function(a){return c.alignTable[a.textAlign+" "+a.textBaseline]||0},noConflict:function(){return a.Flotr=b,this}},a.Flotr=c})(),Flotr.defaultOptions={colors:["#00A8F0","#C0D800","#CB4B4B","#4DA74D","#9440ED"],ieBackgroundColor:"#FFFFFF",title:null,subtitle:null,shadowSize:4,defaultType:null,HtmlText:!0,fontColor:"#545454",fontSize:7.5,resolution:1,parseFloat:!0,xaxis:{ticks:null,minorTicks:null,showLabels:!0,showMinorLabels:!1,labelsAngle:0,title:null,titleAngle:0,noTicks:5,minorTickFreq:null,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscale:!1,autoscaleMargin:0,color:null,mode:"normal",timeFormat:null,timeMode:"UTC",timeUnit:"millisecond",scaling:"linear",base:Math.E,titleAlign:"center",margin:!0},x2axis:{},yaxis:{ticks:null,minorTicks:null,showLabels:!0,showMinorLabels:!1,labelsAngle:0,title:null,titleAngle:90,noTicks:5,minorTickFreq:null,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscale:!1,autoscaleMargin:0,color:null,scaling:"linear",base:Math.E,titleAlign:"center",margin:!0},y2axis:{titleAngle:270},grid:{color:"#545454",backgroundColor:null,backgroundImage:null,watermarkAlpha:.4,tickColor:"#DDDDDD",labelMargin:3,verticalLines:!0,minorVerticalLines:null,horizontalLines:!0,minorHorizontalLines:null,outlineWidth:1,outline:"nsew",circular:!1},mouse:{track:!1,trackAll:!1,position:"se",relative:!1,trackFormatter:Flotr.defaultTrackFormatter,margin:5,lineColor:"#FF3F19",trackDecimals:1,sensibility:2,trackY:!0,radius:3,fillColor:null,fillOpacity:.4}},function(){function b(a,b,c,d){this.rgba=["r","g","b","a"];var e=4;while(-1<--e)this[this.rgba[e]]=arguments[e]||(e==3?1:0);this.normalize()}var a=Flotr._,c={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]};b.prototype={scale:function(b,c,d,e){var f=4;while(-1<--f)a.isUndefined(arguments[f])||(this[this.rgba[f]]*=arguments[f]);return this.normalize()},alpha:function(b){return!a.isUndefined(b)&&!a.isNull(b)&&(this.a=b),this.normalize()},clone:function(){return new b(this.r,this.b,this.g,this.a)},limit:function(a,b,c){return Math.max(Math.min(a,c),b)},normalize:function(){var a=this.limit;return this.r=a(parseInt(this.r,10),0,255),this.g=a(parseInt(this.g,10),0,255),this.b=a(parseInt(this.b,10),0,255),this.a=a(this.a,0,1),this},distance:function(a){if(!a)return;a=new b.parse(a);var c=0,d=3;while(-1<--d)c+=Math.abs(this[this.rgba[d]]-a[this.rgba[d]]);return c},toString:function(){return this.a>=1?"rgb("+[this.r,this.g,this.b].join(",")+")":"rgba("+[this.r,this.g,this.b,this.a].join(",")+")"},contrast:function(){var a=1-(.299*this.r+.587*this.g+.114*this.b)/255;return a<.5?"#000000":"#ffffff"}},a.extend(b,{parse:function(a){if(a instanceof b)return a;var d;if(d=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(a))return new b(parseInt(d[1],16),parseInt(d[2],16),parseInt(d[3],16));if(d=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(a))return new b(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10));if(d=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(a))return new b(parseInt(d[1]+d[1],16),parseInt(d[2]+d[2],16),parseInt(d[3]+d[3],16));if(d=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(a))return new b(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10),parseFloat(d[4]));if(d=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(a))return new b(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55);if(d=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(a))return new b(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55,parseFloat(d[4]));var e=(a+"").replace(/^\s*([\S\s]*?)\s*$/,"$1").toLowerCase();return e=="transparent"?new b(255,255,255,0):(d=c[e])?new b(d[0],d[1],d[2]):new b(0,0,0,0)},processColor:function(c,d){var e=d.opacity;if(!c)return"rgba(0, 0, 0, 0)";if(c instanceof b)return c.alpha(e).toString();if(a.isString(c))return b.parse(c).alpha(e).toString();var f=c.colors?c:{colors:c};if(!d.ctx)return a.isArray(f.colors)?b.parse(a.isArray(f.colors[0])?f.colors[0][1]:f.colors[0]).alpha(e).toString():"rgba(0, 0, 0, 0)";f=a.extend({start:"top",end:"bottom"},f),/top/i.test(f.start)&&(d.x1=0),/left/i.test(f.start)&&(d.y1=0),/bottom/i.test(f.end)&&(d.x2=0),/right/i.test(f.end)&&(d.y2=0);var g,h,i,j=d.ctx.createLinearGradient(d.x1,d.y1,d.x2,d.y2);for(g=0;g=m)break}m=e[p][0],n=e[p][1],n=="year"&&(m=Flotr.getTickSize(f.noTicks*d.year,i,j,0),m==.5&&(n="month",m=6)),a.tickUnit=n,a.tickSize=m;var q=new Date(i),r=m*d[n];switch(n){case"millisecond":s("Milliseconds");break;case"second":s("Seconds");break;case"minute":s("Minutes");break;case"hour":s("Hours");break;case"month":s("Month");break;case"year":s("FullYear")}r>=d.second&&b(q,"Milliseconds",g,0),r>=d.minute&&b(q,"Seconds",g,0),r>=d.hour&&b(q,"Minutes",g,0),r>=d.day&&b(q,"Hours",g,0),r>=d.day*4&&b(q,"Date",g,1),r>=d.year&&b(q,"Month",g,0);var t=0,u=NaN,v;do{v=u,u=q.getTime(),l.push({v:u/h,label:o(u/h,a)});if(n=="month")if(m<1){b(q,"Date",g,1);var w=q.getTime();b(q,"Month",g,c(q,"Month",g)+1);var x=q.getTime();q.setTime(u+t*d.hour+(x-w)*m),t=c(q,"Hours",g),b(q,"Hours",g,0)}else b(q,"Month",g,c(q,"Month",g)+m);else n=="year"?b(q,"FullYear",g,c(q,"FullYear",g)+m):q.setTime(u+r)}while(u0)return{x:b.touches[0].pageX,y:b.touches[0].pageY};if(!a._.isUndefined(b.changedTouches)&&b.changedTouches.length>0)return{x:b.changedTouches[0].pageX,y:b.changedTouches[0].pageY};if(b.pageX||b.pageY)return{x:b.pageX,y:b.pageY};if(b.clientX||b.clientY){var c=document,d=c.body,e=c.documentElement;return{x:b.clientX+d.scrollLeft+e.scrollLeft,y:b.clientY+d.scrollTop+e.scrollTop}}}}}(),function(){var a=Flotr,b=a.DOM,c=a._,d=function(a){this.o=a};d.prototype={dimensions:function(a,b,c,d){return a?this.o.html?this.html(a,this.o.element,c,d):this.canvas(a,b):{width:0,height:0}},canvas:function(b,c){if(!this.o.textEnabled)return;c=c||{};var d=this.measureText(b,c),e=d.width,f=c.size||a.defaultOptions.fontSize,g=c.angle||0,h=Math.cos(g),i=Math.sin(g),j=2,k=6,l;return l={width:Math.abs(h*e)+Math.abs(i*f)+j,height:Math.abs(i*e)+Math.abs(h*f)+k},l},html:function(a,c,d,e){var f=b.create("div");return b.setStyles(f,{position:"absolute",top:"-10000px"}),b.insert(f,'
    '+a+"
    "),b.insert(this.o.element,f),b.size(f)},measureText:function(b,d){var e=this.o.ctx,f;return!e.fillText||a.isIphone&&e.measure?{width:e.measure(b,d)}:(d=c.extend({size:a.defaultOptions.fontSize,weight:1,angle:0},d),e.save(),e.font=(d.weight>1?"bold ":"")+d.size*1.3+"px sans-serif",f=e.measureText(b),e.restore(),f)}},Flotr.Text=d}(),function(){function e(a,c,d){return b.observe.apply(this,arguments),this._handles.push(arguments),this}var a=Flotr.DOM,b=Flotr.EventAdapter,c=Flotr._,d=Flotr;Graph=function(a,e,f){this._setEl(a),this._initMembers(),this._initPlugins(),b.fire(this.el,"flotr:beforeinit",[this]),this.data=e,this.series=d.Series.getSeries(e),this._initOptions(f),this._initGraphTypes(),this._initCanvas(),this._text=new d.Text({element:this.el,ctx:this.ctx,html:this.options.HtmlText,textEnabled:this.textEnabled}),b.fire(this.el,"flotr:afterconstruct",[this]),this._initEvents(),this.findDataRanges(),this.calculateSpacing(),this.draw(c.bind(function(){b.fire(this.el,"flotr:afterinit",[this])},this))},Graph.prototype={destroy:function(){b.fire(this.el,"flotr:destroy"),c.each(this._handles,function(a){b.stopObserving.apply(this,a)}),this._handles=[],this.el.graph=null},observe:e,_observe:e,processColor:function(a,b){var e={x1:0,y1:0,x2:this.plotWidth,y2:this.plotHeight,opacity:1,ctx:this.ctx};return c.extend(e,b),d.Color.processColor(a,e)},findDataRanges:function(){var a=this.axes,b,e,f;c.each(this.series,function(a){f=a.getRange(),f&&(b=a.xaxis,e=a.yaxis,b.datamin=Math.min(f.xmin,b.datamin),b.datamax=Math.max(f.xmax,b.datamax),e.datamin=Math.min(f.ymin,e.datamin),e.datamax=Math.max(f.ymax,e.datamax),b.used=b.used||f.xused,e.used=e.used||f.yused)},this),!a.x.used&&!a.x2.used&&(a.x.used=!0),!a.y.used&&!a.y2.used&&(a.y.used=!0),c.each(a,function(a){a.calculateRange()});var g=c.keys(d.graphTypes),h=!1;c.each(this.series,function(a){if(a.hide)return;c.each(g,function(b){a[b]&&a[b].show&&(this.extendRange(b,a),h=!0)},this),h||this.extendRange(this.options.defaultType,a)},this)},extendRange:function(a,b){this[a].extendRange&&this[a].extendRange(b,b.data,b[a],this[a]),this[a].extendYRange&&this[a].extendYRange(b.yaxis,b.data,b[a],this[a]),this[a].extendXRange&&this[a].extendXRange(b.xaxis,b.data,b[a],this[a])},calculateSpacing:function(){var a=this.axes,b=this.options,d=this.series,e=b.grid.labelMargin,f=this._text,g=a.x,h=a.x2,i=a.y,j=a.y2,k=b.grid.outlineWidth,l,m,n,o;c.each(a,function(a){a.calculateTicks(),a.calculateTextDimensions(f,b)}),o=f.dimensions(b.title,{size:b.fontSize*1.5},"font-size:1em;font-weight:bold;","flotr-title"),this.titleHeight=o.height,o=f.dimensions(b.subtitle,{size:b.fontSize},"font-size:smaller;","flotr-subtitle"),this.subtitleHeight=o.height;for(m=0;m1&&(this.multitouches=c.touches),b.fire(a,"flotr:mousedown",[event,this]),this.observe(document,"touchend",d)},this)),this.observe(this.overlay,"touchmove",c.bind(function(c){var d=this.getEventPosition(c);c.preventDefault(),e=!0,this.multitouches||c.touches&&c.touches.length>1?this.multitouches=c.touches:f||b.fire(a,"flotr:mousemove",[event,d,this]),this.lastMousePos=d},this))):this.observe(this.overlay,"mousedown",c.bind(this.mouseDownHandler,this)).observe(a,"mousemove",c.bind(this.mouseMoveHandler,this)).observe(this.overlay,"click",c.bind(this.clickHandler,this)).observe(a,"mouseout",function(){b.fire(a,"flotr:mouseout")})},_initCanvas:function(){function k(e,f){return e||(e=a.create("canvas"),typeof FlashCanvas!="undefined"&&typeof e.getContext=="function"&&FlashCanvas.initElement(e),e.className="flotr-"+f,e.style.cssText="position:absolute;left:0px;top:0px;",a.insert(b,e)),c.each(i,function(b,c){a.show(e);if(f=="canvas"&&e.getAttribute(c)===b)return;e.setAttribute(c,b*d.resolution),e.style[c]=b+"px"}),e.context_=null,e}function l(a){window.G_vmlCanvasManager&&window.G_vmlCanvasManager.initElement(a);var b=a.getContext("2d");return window.G_vmlCanvasManager||b.scale(d.resolution,d.resolution),b}var b=this.el,d=this.options,e=b.children,f=[],g,h,i,j;for(h=e.length;h--;)g=e[h],!this.canvas&&g.className==="flotr-canvas"?this.canvas=g:!this.overlay&&g.className==="flotr-overlay"?this.overlay=g:f.push(g);for(h=f.length;h--;)b.removeChild(f[h]);a.setStyles(b,{position:"relative"}),i={},i.width=b.clientWidth,i.height=b.clientHeight;if(i.width<=0||i.height<=0||d.resolution<=0)throw"Invalid dimensions for plot, width = "+i.width+", height = "+i.height+", resolution = "+d.resolution;this.canvas=k(this.canvas,"canvas"),this.overlay=k(this.overlay,"overlay"),this.ctx=l(this.canvas),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.octx=l(this.overlay),this.octx.clearRect(0,0,this.overlay.width,this.overlay.height),this.canvasHeight=i.height,this.canvasWidth=i.width,this.textEnabled=!!this.ctx.drawText||!!this.ctx.fillText},_initPlugins:function(){c.each(d.plugins,function(a,b){c.each(a.callbacks,function(a,b){this.observe(this.el,b,c.bind(a,this))},this),this[b]=d.clone(a),c.each(this[b],function(a,d){c.isFunction(a)&&(this[b][d]=c.bind(a,this))},this)},this)},_initOptions:function(a){var e=d.clone(d.defaultOptions);e.x2axis=c.extend(c.clone(e.xaxis),e.x2axis),e.y2axis=c.extend(c.clone(e.yaxis),e.y2axis),this.options=d.merge(a||{},e),this.options.grid.minorVerticalLines===null&&this.options.xaxis.scaling==="logarithmic"&&(this.options.grid.minorVerticalLines=!0),this.options.grid.minorHorizontalLines===null&&this.options.yaxis.scaling==="logarithmic"&&(this.options.grid.minorHorizontalLines=!0),b.fire(this.el,"flotr:afterinitoptions",[this]),this.axes=d.Axis.getAxes(this.options);var f=[],g=[],h=this.series.length,i=this.series.length,j=this.options.colors,k=[],l=0,m,n,o,p;for(n=i-1;n>-1;--n)m=this.series[n].color,m&&(--i,c.isNumber(m)?f.push(m):k.push(d.Color.parse(m)));for(n=f.length-1;n>-1;--n)i=Math.max(i,f[n]+1);for(n=0;g.length=j.length&&(n=0,++l)}for(n=0,o=0;n10?b.minorTickFreq=0:g-h>5?b.minorTickFreq=2:b.minorTickFreq=5)}else a.tickSize=Flotr.getTickSize(b.noTicks,c,d,b.tickDecimals);a.min=c,a.max=d,b.min===null&&b.autoscale&&(a.min-=a.tickSize*e,a.min<0&&a.datamin>=0&&(a.min=0),a.min=a.tickSize*Math.floor(a.min/a.tickSize)),b.max===null&&b.autoscale&&(a.max+=a.tickSize*e,a.max>0&&a.datamax<=0&&a.datamax!=a.datamin&&(a.max=0),a.max=a.tickSize*Math.ceil(a.max/a.tickSize)),a.min==a.max&&(a.max=a.min+1)},calculateTextDimensions:function(a,b){var c="",d,e;if(this.options.showLabels)for(e=0;ec.length&&(c=this.ticks[e].label);this.maxLabel=a.dimensions(c,{size:b.fontSize,angle:Flotr.toRad(this.options.labelsAngle)},"font-size:smaller;","flotr-grid-label"),this.titleSize=a.dimensions(this.options.title,{size:b.fontSize*1.2,angle:Flotr.toRad(this.options.titleAngle)},"font-weight:bold;","flotr-axis-title")},_cleanUserTicks:function(b,c){var d=this,e=this.options,f,g,h,i;a.isFunction(b)&&(b=b({min:d.min,max:d.max}));for(g=0;g1?i[1]:e.tickFormatter(f,{min:d.min,max:d.max})):(f=i,h=e.tickFormatter(f,{min:this.min,max:this.max})),c[g]={v:f,label:h}},_calculateTimeTicks:function(){this.ticks=Flotr.Date.generator(this)},_calculateLogTicks:function(){var a=this,b=a.options,c,d,e=Math.log(a.max);b.base!=Math.E&&(e/=Math.log(b.base)),e=Math.ceil(e);var f=Math.log(a.min);b.base!=Math.E&&(f/=Math.log(b.base)),f=Math.ceil(f);for(i=f;ie&&(e=i,g=!0),jf&&(f=j,h=!0);return{xmin:c,xmax:e,ymin:d,ymax:f,xused:g,yused:h}}},a.extend(b,{getSeries:function(c){return a.map(c,function(c){var d;return c.data?(d=new b,a.extend(d,c)):d=new b({data:c}),d})}}),Flotr.Series=b}(),Flotr.addType("lines",{options:{show:!1,lineWidth:2,fill:!1,fillBorder:!1,fillColor:null,fillOpacity:.4,steps:!1,stacked:!1},stack:{values:[]},draw:function(a){var b=a.context,c=a.lineWidth,d=a.shadowSize,e;b.save(),b.lineJoin="round",d&&(b.lineWidth=d/2,e=c/2+b.lineWidth/2,b.strokeStyle="rgba(0,0,0,0.1)",this.plot(a,e+d/2,!1),b.strokeStyle="rgba(0,0,0,0.2)",this.plot(a,e,!1)),b.lineWidth=c,b.strokeStyle=a.color,this.plot(a,0,!0),b.restore()},plot:function(a,b,c){var d=a.context,e=a.width,f=a.height,g=a.xScale,h=a.yScale,i=a.data,j=a.stacked?this.stack:!1,k=i.length-1,l=null,m=null,n=h(0),o,p,q,r,s,t,u;if(k<1)return;d.beginPath();for(u=0;uf&&r>f||q<0&&r<0||o<0&&p<0||o>e&&p>e)continue;(l!=o||m!=q+b)&&d.moveTo(o,q+b),l=p,m=r+b,a.steps?(d.lineTo(l+b/2,q+b),d.lineTo(l+b/2,m)):d.lineTo(l,m)}(!a.fill||a.fill&&!a.fillBorder)&&d.stroke(),!b&&a.fill&&(o=g(i[0][0]),d.fillStyle=a.fillStyle,d.lineTo(p,n),d.lineTo(o,n),d.lineTo(o,h(i[0][1])),d.fill(),a.fillBorder&&d.stroke()),d.closePath()},extendYRange:function(a,b,c,d){var e=a.options;if(c.stacked&&(!e.max&&e.max!==0||!e.min&&e.min!==0)){var f=a.max,g=a.min,h=d.positiveSums||{},i=d.negativeSums||{},j,k;for(k=0;k0?(h[j]=(h[j]||0)+b[k][1],f=Math.max(f,h[j])):(i[j]=(i[j]||0)+b[k][1],g=Math.min(g,i[j]));d.negativeSums=i,d.positiveSums=h,a.max=f,a.min=g}c.steps&&(this.hit=function(a){var b=a.data,c=a.args,d=a.yScale,e=c[0],f=b.length,g=c[1],h=e.x,i=e.relY,j;for(j=0;j=b[j][0]&&h<=b[j+1][0]){Math.abs(d(b[j][1])-i)<8&&(g.x=b[j][0],g.y=b[j][1],g.index=j,g.seriesIndex=a.index);break}},this.drawHit=function(a){var b=a.context,c=a.args,d=a.data,e=a.xScale,f=c.index,g=e(c.x),h=a.yScale(c.y),i;d.length-1>f&&(i=a.xScale(d[f+1][0]),b.save(),b.strokeStyle=a.color,b.lineWidth=a.lineWidth,b.beginPath(),b.moveTo(g,h),b.lineTo(i,h),b.stroke(),b.closePath(),b.restore())},this.clearHit=function(a){var b=a.context,c=a.args,d=a.data,e=a.xScale,f=a.lineWidth,g=c.index,h=e(c.x),i=a.yScale(c.y),j;d.length-1>g&&(j=a.xScale(d[g+1][0]),b.clearRect(h-f,i-f,j-h+2*f,2*f))})}}),Flotr.addType("bars",{options:{show:!1,lineWidth:2,barWidth:1,fill:!0,fillColor:null,fillOpacity:.4,horizontal:!1,stacked:!1,centered:!0,topPadding:.1},stack:{positive:[],negative:[],_positive:[],_negative:[]},draw:function(a){var b=a.context;b.save(),b.lineJoin="miter",b.lineWidth=a.lineWidth,b.strokeStyle=a.color,a.fill&&(b.fillStyle=a.fillStyle),this.plot(a),b.restore()},plot:function(a){var b=a.data,c=a.context,d=a.shadowSize,e,f,g,h,i,j;if(b.length<1)return;this.translate(c,a.horizontal);for(e=0;e0?g.positive:g.negative,n=o[l]||n,o[l]=n+m),p=j(l-i),q=j(l+e-i),r=k(m+n),s=k(n),s<0&&(s=0),a===null||b===null?null:{x:l,y:m,xScale:j,yScale:k,top:r,left:Math.min(p,q)-h/2,width:Math.abs(q-p)-h,height:s-r}},hit:function(a){var b=a.data,c=a.args,d=c[0],e=c[1],f=d.x,g=d.y,h=this.getBarGeometry(f,g,a),i=h.width/2,j=h.left,k,l;for(l=b.length;l--;)k=this.getBarGeometry(b[l][0],b[l][1],a),k.y>h.y&&Math.abs(j-k.left)0?(j[l]=(j[l]||0)+m,g=Math.max(g,j[l])):(k[l]=(k[l]||0)+m,f=Math.min(f,k[l]));(i==1&&h||i==-1&&!h)&&c.topPadding&&(a.max===a.datamax||c.stacked&&this.stackMax!==g)&&(g+=c.topPadding*(g-f)),this.stackMin=f,this.stackMax=g,this.negativeSums=k,this.positiveSums=j,a.max=g,a.min=f}}),Flotr.addType("bubbles",{options:{show:!1,lineWidth:2,fill:!0,fillOpacity:.4,baseRadius:2},draw:function(a){var b=a.context,c=a.shadowSize;b.save(),b.lineWidth=a.lineWidth,b.fillStyle="rgba(0,0,0,0.05)",b.strokeStyle="rgba(0,0,0,0.05)",this.plot(a,c/2),b.strokeStyle="rgba(0,0,0,0.1)",this.plot(a,c/4),b.strokeStyle=a.color,b.fillStyle=a.fillStyle,this.plot(a),b.restore()},plot:function(a,b){var c=a.data,d=a.context,e,f,g,h,i;b=b||0;for(f=0;fr?"downFillColor":"upFillColor"],a.fill&&!a.barcharts&&(c.fillStyle="rgba(0,0,0,0.05)",c.fillRect(s+g,x+g,t-s,w-x),c.save(),c.globalAlpha=a.fillOpacity,c.fillStyle=k,c.fillRect(s,x+h,t-s,w-x),c.restore());if(h||i)m=Math.floor((s+t)/2)+j,c.strokeStyle=k,c.beginPath(),a.barcharts?(c.moveTo(m,Math.floor(v+f)),c.lineTo(m,Math.floor(u+f)),n=Math.floor(o+f)+.5,c.moveTo(Math.floor(s)+j,n),c.lineTo(m,n),n=Math.floor(r+f)+.5,c.moveTo(Math.floor(t)+j,n),c.lineTo(m,n)):(c.strokeRect(s,x+h,t-s,w-x),c.moveTo(m,Math.floor(x+h)),c.lineTo(m,Math.floor(v+h)),c.moveTo(m,Math.floor(w+h)),c.lineTo(m,Math.floor(u+h))),c.closePath(),c.stroke()}},extendXRange:function(a,b,c){a.options.max===null&&(a.max=Math.max(a.datamax+.5,a.max),a.min=Math.min(a.datamin-.5,a.min))}}),Flotr.addType("gantt",{options:{show:!1,lineWidth:2,barWidth:1,fill:!0,fillColor:null,fillOpacity:.4,centered:!0},draw:function(a){var b=this.ctx,c=a.gantt.barWidth,d=Math.min(a.gantt.lineWidth,c);b.save(),b.translate(this.plotOffset.left,this.plotOffset.top),b.lineJoin="miter",b.lineWidth=d,b.strokeStyle=a.color,b.save(),this.gantt.plotShadows(a,c,0,a.gantt.fill),b.restore();if(a.gantt.fill){var e=a.gantt.fillColor||a.color;b.fillStyle=this.processColor(e,{opacity:a.gantt.fillOpacity})}this.gantt.plot(a,c,0,a.gantt.fill),b.restore()},plot:function(a,b,c,d){var e=a.data;if(e.length<1)return;var f=a.xaxis,g=a.yaxis,h=this.ctx,i;for(i=0;if.max||sg.max)continue;pf.max&&(q=f.max,f.lastSerie!=a&&(n=!1)),rg.max&&(s=g.max,g.lastSerie!=a&&(n=!1)),d&&(h.beginPath(),h.moveTo(f.d2p(p),g.d2p(r)+c),h.lineTo(f.d2p(p),g.d2p(s)+c),h.lineTo(f.d2p(q),g.d2p(s)+c),h.lineTo(f.d2p(q),g.d2p(r)+c),h.fill(),h.closePath()),a.gantt.lineWidth&&(m||o||n)&&(h.beginPath(),h.moveTo(f.d2p(p),g.d2p(r)+c),h[m?"lineTo":"moveTo"](f.d2p(p),g.d2p(s)+c),h[n?"lineTo":"moveTo"](f.d2p(q),g.d2p(s)+c),h[o?"lineTo":"moveTo"](f.d2p(q),g.d2p(r)+c),h.stroke(),h.closePath())}},plotShadows:function(a,b,c){var d=a.data;if(d.length<1)return;var e,f,g,h,i=a.xaxis,j=a.yaxis,k=this.ctx,l=this.options.shadowSize;for(e=0;ei.max||pj.max)continue;mi.max&&(n=i.max),oj.max&&(p=j.max);var q=i.d2p(n)-i.d2p(m)-(i.d2p(n)+l<=this.plotWidth?0:l),r=j.d2p(o)-j.d2p(p)-(j.d2p(o)+l<=this.plotHeight?0:l);k.fillStyle="rgba(0,0,0,0.05)",k.fillRect(Math.min(i.d2p(m)+l,this.plotWidth),Math.min(j.d2p(p)+l,this.plotHeight),q,r)}},extendXRange:function(a){if(a.options.max===null){var b=a.min,c=a.max,d,e,f,g,h,i={},j={},k=null;for(d=0;db&&(b=a.max+g.barWidth)}}a.lastSerie=j,a.max=b,a.min=c,a.tickSize=Flotr.getTickSize(a.options.noTicks,c,b,a.options.tickDecimals)}}}),function(){function a(a){return typeof a=="object"&&a.constructor&&(Image?!0:a.constructor===Image)}Flotr.defaultMarkerFormatter=function(a){return Math.round(a.y*100)/100+""},Flotr.addType("markers",{options:{show:!1,lineWidth:1,color:"#000000",fill:!1,fillColor:"#FFFFFF",fillOpacity:.4,stroke:!1,position:"ct",verticalMargin:0,labelFormatter:Flotr.defaultMarkerFormatter,fontSize:Flotr.defaultOptions.fontSize,stacked:!1,stackingType:"b",horizontal:!1},stack:{positive:[],negative:[],values:[]},draw:function(a){function m(a,b){return g=d.negative[a]||0,f=d.positive[a]||0,b>0?(d.positive[a]=g+b,g+b):(d.negative[a]=f+b,f+b)}var b=a.data,c=a.context,d=a.stacked?a.stack:!1,e=a.stackingType,f,g,h,i,j,k,l;c.save(),c.lineJoin="round",c.lineWidth=a.lineWidth,c.strokeStyle="rgba(0,0,0,0.5)",c.fillStyle=a.fillStyle;for(i=0;i0?"top":"bottom",B,C,D,x,y;c.save(),c.translate(i/2,h/2),c.scale(1,q),C=Math.cos(u)*j,D=Math.sin(u)*j,f>0&&(this.plotSlice(C+f,D+f,n,s,t,c),l&&(c.fillStyle="rgba(0,0,0,0.1)",c.fill())),this.plotSlice(C,D,n,s,t,c),l&&(c.fillStyle=m,c.fill()),c.lineWidth=e,c.strokeStyle=k,c.stroke(),B={size:a.fontSize*1.2,color:a.fontColor,weight:1.5},v&&(a.htmlText||!a.textEnabled?(divStyle="position:absolute;"+A+":"+(h/2+(A==="top"?y:-y))+"px;",divStyle+=z+":"+(i/2+(z==="right"?-x:x))+"px;",p.push('
    ',v,"
    ")):(B.textAlign=z,B.textBaseline=A,Flotr.drawText(c,v,x,y,B)));if(a.htmlText||!a.textEnabled){var E=Flotr.DOM.node('
    ');Flotr.DOM.insert(E,p.join("")),Flotr.DOM.insert(a.element,E)}c.restore(),this.startAngle=t,this.slices=this.slices||[],this.slices.push({radius:Math.min(d.width,d.height)*g/2,x:C,y:D,explode:j,start:s,end:t})},plotSlice:function(a,b,c,d,e,f){f.beginPath(),f.moveTo(a,b),f.arc(a,b,c,d,e,!1),f.lineTo(a,b),f.closePath()},hit:function(a){var b=a.data[0],c=a.args,d=a.index,e=c[0],f=c[1],g=this.slices[d],h=e.relX-a.width/2,i=e.relY-a.height/2,j=Math.sqrt(h*h+i*i),k=Math.atan(i/h),l=Math.PI*2,m=g.explode||a.explode,n=g.start%l,o=g.end%l;h<0?k+=Math.PI:h>0&&i<0&&(k+=l),jm&&(n>o&&(kn)||k>n&&k0&&(b.lineWidth=d/2,b.strokeStyle="rgba(0,0,0,0.1)",this.plot(a,d/2+b.lineWidth/2),b.strokeStyle="rgba(0,0,0,0.2)",this.plot(a,b.lineWidth/2)),b.lineWidth=a.lineWidth,b.strokeStyle=a.color,b.fillStyle=a.fillColor||a.color,this.plot(a),b.restore()},plot:function(a,b){var c=a.data,d=a.context,e=a.xScale,f=a.yScale,g,h,i;for(g=c.length-1;g>-1;--g){i=c[g][1];if(i===null)continue;h=e(c[g][0]),i=f(i);if(h<0||h>a.width||i<0||i>a.height)continue;d.beginPath(),b?d.arc(h,i+b,a.radius,0,Math.PI,!1):(d.arc(h,i,a.radius,0,2*Math.PI,!0),a.fill&&d.fill()),d.stroke(),d.closePath()}}}),Flotr.addType("radar",{options:{show:!1,lineWidth:2,fill:!0,fillOpacity:.4,radiusRatio:.9},draw:function(a){var b=a.context,c=a.shadowSize;b.save(),b.translate(a.width/2,a.height/2),b.lineWidth=a.lineWidth,b.fillStyle="rgba(0,0,0,0.05)",b.strokeStyle="rgba(0,0,0,0.05)",this.plot(a,c/2),b.strokeStyle="rgba(0,0,0,0.1)",this.plot(a,c/4),b.strokeStyle=a.color,b.fillStyle=a.fillStyle,this.plot(a),b.restore()},plot:function(a,b){var c=a.data,d=a.context,e=Math.min(a.height,a.width)*a.radiusRatio/2,f=2*Math.PI/c.length,g=-Math.PI/2,h,i;b=b||0,d.beginPath();for(h=0;hthis.plotWidth||b.relY>this.plotHeight){this.el.style.cursor=null,a.removeClass(this.el,"flotr-crosshair");return}d.hideCursor&&(this.el.style.cursor="none",a.addClass(this.el,"flotr-crosshair")),c.save(),c.strokeStyle=d.color,c.lineWidth=1,c.beginPath(),d.mode.indexOf("x")!=-1&&(c.moveTo(f,e.top),c.lineTo(f,e.top+this.plotHeight)),d.mode.indexOf("y")!=-1&&(c.moveTo(e.left,g),c.lineTo(e.left+this.plotWidth,g)),c.stroke(),c.restore()},clearCrosshair:function(){var a=this.plotOffset,b=this.lastMousePos,c=this.octx;b&&(c.clearRect(b.relX+a.left,a.top,1,this.plotHeight+1),c.clearRect(a.left,b.relY+a.top,this.plotWidth+1,1))}})}(),function(){function c(a,b,c,d){var e="image/"+a,f=b.toDataURL(e),g=new Image;return g.src=f,g}var a=Flotr.DOM,b=Flotr._;Flotr.addPlugin("download",{saveImage:function(d,e,f,g){var h=null;if(Flotr.isIE&&Flotr.isIE<9)return h=""+this.canvas.firstChild.innerHTML+"",window.open().document.write(h);if(d!=="jpeg"&&d!=="png")return;h=c(d,this.canvas,e,f);if(b.isElement(h)&&g)this.download.restoreCanvas(),a.hide(this.canvas),a.hide(this.overlay),a.setStyles({position:"absolute"}),a.insert(this.el,h),this.saveImageElement=h;else return window.open(h.src)},restoreCanvas:function(){a.show(this.canvas),a.show(this.overlay),this.saveImageElement&&this.el.removeChild(this.saveImageElement),this.saveImageElement=null}})}(),function(){var a=Flotr.EventAdapter,b=Flotr._;Flotr.addPlugin("graphGrid",{callbacks:{"flotr:beforedraw":function(){this.graphGrid.drawGrid()},"flotr:afterdraw":function(){this.graphGrid.drawOutline()}},drawGrid:function(){function p(a){for(n=0;n=l.max||(a==l.min||a==l.max)&&e.outlineWidth)return;d(Math.floor(l.d2p(a))+c.lineWidth/2)})}function r(a){c.moveTo(a,0),c.lineTo(a,j)}function s(a){c.moveTo(0,a),c.lineTo(k,a)}var c=this.ctx,d=this.options,e=d.grid,f=e.verticalLines,g=e.horizontalLines,h=e.minorVerticalLines,i=e.minorHorizontalLines,j=this.plotHeight,k=this.plotWidth,l,m,n,o;(f||h||g||i)&&a.fire(this.el,"flotr:beforegrid",[this.axes.x,this.axes.y,d,this]),c.save(),c.lineWidth=1,c.strokeStyle=e.tickColor;if(e.circular){c.translate(this.plotOffset.left+k/2,this.plotOffset.top+j/2);var t=Math.min(j,k)*d.radar.radiusRatio/2,u=this.axes.x.ticks.length,v=2*(Math.PI/u),w=-Math.PI/2;c.beginPath(),l=this.axes.y,g&&p(l.ticks),i&&p(l.minorTicks),f&&b.times(u,function(a){c.moveTo(0,0),c.lineTo(Math.cos(a*v+w)*t,Math.sin(a*v+w)*t)}),c.stroke()}else c.translate(this.plotOffset.left,this.plotOffset.top),e.backgroundColor&&(c.fillStyle=this.processColor(e.backgroundColor,{x1:0,y1:0,x2:k,y2:j}),c.fillRect(0,0,k,j)),c.beginPath(),l=this.axes.x,f&&q(l.ticks,r),h&&q(l.minorTicks,r),l=this.axes.y,g&&q(l.ticks,s),i&&q(l.minorTicks,s),c.stroke();c.restore(),(f||h||g||i)&&a.fire(this.el,"flotr:aftergrid",[this.axes.x,this.axes.y,d,this])},drawOutline:function(){var a=this,b=a.options,c=b.grid,d=c.outline,e=a.ctx,f=c.backgroundImage,g=a.plotOffset,h=g.left,j=g.top,k=a.plotWidth,l=a.plotHeight,m,n,o,p,q,r;if(!c.outlineWidth)return;e.save();if(c.circular){e.translate(h+k/2,j+l/2);var s=Math.min(l,k)*b.radar.radiusRatio/2,t=this.axes.x.ticks.length,u=2*(Math.PI/t),v=-Math.PI/2;e.beginPath(),e.lineWidth=c.outlineWidth,e.strokeStyle=c.color,e.lineJoin="round";for(i=0;i<=t;++i)e[i===0?"moveTo":"lineTo"](Math.cos(i*u+v)*s,Math.sin(i*u+v)*s);e.stroke()}else{e.translate(h,j);var w=c.outlineWidth,x=.5-w+(w+1)%2/2,y="lineTo",z="moveTo";e.lineWidth=w,e.strokeStyle=c.color,e.lineJoin="miter",e.beginPath(),e.moveTo(x,x),k-=w/2%1,l+=w/2,e[d.indexOf("n")!==-1?y:z](k,x),e[d.indexOf("e")!==-1?y:z](k,l),e[d.indexOf("s")!==-1?y:z](x,l),e[d.indexOf("w")!==-1?y:z](x,x),e.stroke(),e.closePath()}e.restore(),f&&(o=f.src||f,p=(parseInt(f.left,10)||0)+g.left,q=(parseInt(f.top,10)||0)+g.top,n=new Image,n.onload=function(){e.save(),f.alpha&&(e.globalAlpha=f.alpha),e.globalCompositeOperation="destination-over",e.drawImage(n,0,0,n.width,n.height,p,q,k,l),e.restore()},n.src=o)}})}(),function(){var a=Flotr.DOM,b=Flotr._,c=Flotr,d="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;";Flotr.addPlugin("hit",{callbacks:{"flotr:mousemove":function(a,b){this.hit.track(b)},"flotr:click":function(a){this.hit.track(a)},"flotr:mouseout":function(){this.hit.clearHit()}},track:function(a){(this.options.mouse.track||b.any(this.series,function(a){return a.mouse&&a.mouse.track}))&&this.hit.hit(a)},executeOnType:function(a,d,e){function h(a,h){b.each(b.keys(c.graphTypes),function(b){a[b]&&a[b].show&&this[b][d]&&(g=this.getOptions(a,b),g.fill=!!a.mouse.fillColor,g.fillStyle=this.processColor(a.mouse.fillColor||"#ffffff",{opacity:a.mouse.fillOpacity}),g.color=a.mouse.lineColor,g.context=this.octx,g.index=h,e&&(g.args=e),this[b][d].call(this[b],g),f=!0)},this)}var f=!1,g;return b.isArray(a)||(a=[a]),b.each(a,h,this),f},drawHit:function(a){var b=this.octx,c=a.series;if(c.mouse.lineColor){b.save(),b.lineWidth=c.points?c.points.lineWidth:1,b.strokeStyle=c.mouse.lineColor,b.fillStyle=this.processColor(c.mouse.fillColor||"#ffffff",{opacity:c.mouse.fillOpacity}),b.translate(this.plotOffset.left,this.plotOffset.top);if(!this.hit.executeOnType(c,"drawHit",a)){var d=a.xaxis,e=a.yaxis;b.beginPath(),b.arc(d.d2p(a.x),e.d2p(a.y),c.points.radius||c.mouse.radius,0,2*Math.PI,!0),b.fill(),b.stroke(),b.closePath()}b.restore()}this.prevHit=a},clearHit:function(){var b=this.prevHit,c=this.octx,d=this.plotOffset;c.save(),c.translate(d.left,d.top);if(b){if(!this.hit.executeOnType(b.series,"clearHit",this.prevHit)){var e=b.series,f=e.points?e.points.lineWidth:1;offset=(e.points.radius||e.mouse.radius)+f,c.clearRect(b.xaxis.d2p(b.x)-offset,b.yaxis.d2p(b.y)-offset,offset*2,offset*2)}a.hide(this.mouseTrack),this.prevHit=null}c.restore()},hit:function(a){var c=this.options,d=this.prevHit,e,f,g,h,i,j,k,l;if(this.series.length===0)return;n={relX:a.relX,relY:a.relY,absX:a.absX,absY:a.absY};if(c.mouse.trackY&&!c.mouse.trackAll&&this.hit.executeOnType(this.series,"hit",[a,n]))b.isUndefined(n.seriesIndex)||(i=this.series[n.seriesIndex],n.series=i,n.mouse=i.mouse,n.xaxis=i.xaxis,n.yaxis=i.yaxis);else{e=this.hit.closest(a);if(e){e=c.mouse.trackY?e.point:e.x,h=e.seriesIndex,i=this.series[h],k=i.xaxis,l=i.yaxis,f=2*i.mouse.sensibility;if(c.mouse.trackAll||e.distanceXk.xaxis.max)continue;n=Math.abs(p-d),o=Math.abs(q-e),m=n*n+o*o,m
    '),this.mouseTrack=i,a.insert(this.el,i));if(!b.mouse.relative)f.charAt(0)=="n"?c+="top:"+(g+n)+"px;bottom:auto;":f.charAt(0)=="s"&&(c+="bottom:"+(g+m)+"px;top:auto;"),f.charAt(1)=="e"?c+="right:"+(g+l)+"px;left:auto;":f.charAt(1)=="w"&&(c+="left:"+(g+k)+"px;right:auto;");else if(e.bars.show)c+="bottom:"+(g-n-b.yaxis.d2p(b.y/2)+this.canvasHeight)+"px;top:auto;",c+="left:"+(g+k+b.xaxis.d2p(b.x-p.bars.barWidth/2))+"px;right:auto;";else if(e.pie.show){var q={x:this.plotWidth/2,y:this.plotHeight/2},r=Math.min(this.canvasWidth,this.canvasHeight)*e.pie.sizeRatio/2,s=b.sAngle=5||Math.abs(a.second.y-a.first.y)>=5}})}(),function(){var a=Flotr.DOM;Flotr.addPlugin("labels",{callbacks:{"flotr:afterdraw":function(){this.labels.draw()}},draw:function(){function s(a,b,d){var e=d?b.minorTicks:b.ticks,f=b.orientation===1,h=b.n===1,k,m;k={color:b.options.color||o.grid.color,angle:Flotr.toRad(b.options.labelsAngle),textBaseline:"middle"};for(l=0;l(f?a.plotWidth:a.plotHeight))continue;Flotr.drawText(p,c.label,k(a,f,g,i),m(a,f,g,i),h),!f&&!g&&(p.save(),p.strokeStyle=h.color,p.beginPath(),p.moveTo(a.plotOffset.left+a.plotWidth-8,a.plotOffset.top+b.d2p(c.v)),p.lineTo(a.plotOffset.left+a.plotWidth,a.plotOffset.top+b.d2p(c.v)),p.stroke(),p.restore())}}function u(a,b){var d=b.orientation===1,e=b.n===1,g="",h,i,j,k=a.plotOffset;!d&&!e&&(p.save(),p.strokeStyle=b.options.color||o.grid.color,p.beginPath());if(b.options.showLabels&&(e?!0:b.used))for(l=0;l(d?a.canvasWidth:a.canvasHeight))continue;j=k.top+(d?(e?1:-1)*(a.plotHeight+o.grid.labelMargin):b.d2p(c.v)-b.maxLabel.height/2),h=d?k.left+b.d2p(c.v)-f/2:0,g="",l===0?g=" first":l===b.ticks.length-1&&(g=" last"),g+=d?" flotr-grid-label-x":" flotr-grid-label-y",m+=['
    '+c.label+"
    "].join(" "),!d&&!e&&(p.moveTo(k.left+a.plotWidth-8,k.top+b.d2p(c.v)),p.lineTo(k.left+a.plotWidth,k.top+b.d2p(c.v)))}}var b,c,d,e,f,g,h,i,j,k,l,m="",n=0,o=this.options,p=this.ctx,q=this.axes,r={size:o.fontSize};for(l=0;l-1;--m){if(!c[m].label||c[m].hide)continue;n=f.labelFormatter(c[m].label),v=Math.max(v,this._text.measureText(n,p).width)}var w=Math.round(q+s*3+v),x=Math.round(j*(s+r)+s);k.charAt(0)=="s"&&(u=d.top+this.plotHeight-(l+x)),k.charAt(1)=="e"&&(t=d.left+this.plotWidth-(l+w)),o=this.processColor(f.backgroundColor||"rgb(240,240,240)",{opacity:f.backgroundOpacity||.1}),i.fillStyle=o,i.fillRect(t,u,w,x),i.strokeStyle=f.labelBoxBorderColor,i.strokeRect(Flotr.toPixel(t),Flotr.toPixel(u),w,x);var y=t+s,z=u+s;for(m=0;m
    ":""),h=!0);var A=c[m],B=f.labelBoxWidth,C=f.labelBoxHeight,E=A.bars?A.bars.fillOpacity:f.labelBoxOpacity,F="opacity:"+E+";filter:alpha(opacity="+E*100+");";n=f.labelFormatter(A.label),o="background-color:"+(A.bars&&A.bars.show&&A.bars.fillColor&&A.bars.fill?A.bars.fillColor:A.color)+";",g.push('",'")}h&&g.push("");if(g.length>0){var G='
     '+(serie.label || String.fromCharCode(65+i))+'
    ','
    ','
    ','
    ',"
    ","
    ","
    ',n,"
    '+g.join("")+"
    ";if(f.container)a.insert(f.container,G);else{var H={position:"absolute","z-index":2};k.charAt(0)=="n"?(H.top=l+d.top+"px",H.bottom="auto"):k.charAt(0)=="s"&&(H.bottom=l+d.bottom+"px",H.top="auto"),k.charAt(1)=="e"?(H.right=l+d.right+"px",H.left="auto"):k.charAt(1)=="w"&&(H.left=l+d.left+"px",H.right="auto");var I=a.create("div"),J;I.className="flotr-legend",a.setStyles(I,H),a.insert(I,G),a.insert(this.el,I);if(!f.backgroundOpacity)return;var K=f.backgroundColor||e.grid.backgroundColor||"#ffffff";b.extend(H,a.size(I),{backgroundColor:K,"z-index":1}),H.width+="px",H.height+="px",I=a.create("div"),I.className="flotr-legend-bg",a.setStyles(I,H),a.opacity(I,f.backgroundOpacity),a.insert(I," "),a.insert(this.el,I)}}}}})}(),function(){function a(a){if(this.options.spreadsheet.tickFormatter)return this.options.spreadsheet.tickFormatter(a);var b=c.find(this.axes.x.ticks,function(b){return b.v==a});return b?b.label:a}var b=Flotr.DOM,c=Flotr._;Flotr.addPlugin("spreadsheet",{options:{show:!1,tabGraphLabel:"Graph",tabDataLabel:"Data",toolbarDownload:"Download CSV",toolbarSelectAll:"Select all",csvFileSeparator:",",decimalSeparator:".",tickFormatter:null,initialTab:"graph"},callbacks:{"flotr:afterconstruct":function(){if(!this.options.spreadsheet.show)return;var a=this.spreadsheet,c=b.node('
    '),d=b.node('
    '+this.options.spreadsheet.tabGraphLabel+"
    "),e=b.node('
    '+this.options.spreadsheet.tabDataLabel+"
    "),f;a.tabsContainer=c,a.tabs={graph:d,data:e},b.insert(c,d),b.insert(c,e),b.insert(this.el,c),f=b.size(e).height+2,this.plotOffset.bottom+=f,b.setStyles(c,{top:this.canvasHeight-f+"px"}),this.observe(d,"click",function(){a.showTab("graph")}).observe(e,"click",function(){a.showTab("data")}),this.options.spreadsheet.initialTab!=="graph"&&a.showTab(this.options.spreadsheet.initialTab)}},loadDataGrid:function(){if(this.seriesData)return this.seriesData;var a=this.series,b={};return c.each(a,function(a,d){c.each(a.data,function(a){var c=a[0],e=a[1],f=b[c];if(f)f[d+1]=e;else{var g=[];g[0]=c,g[d+1]=e,b[c]=g}})}),this.seriesData=c.sortBy(b,function(a,b){return parseInt(b,10)}),this.seriesData},constructDataGrid:function(){if(this.spreadsheet.datagrid)return this.spreadsheet.datagrid;var d=this.series,e=this.spreadsheet.loadDataGrid(),f=[""],g,h,i,j=[''];j.push(""),c.each(d,function(a,b){j.push('"),f.push("")}),j.push(""),c.each(e,function(b){j.push(""),c.times(d.length+1,function(d){var e="td",f=b[d],g=c.isUndefined(f)?"":Math.round(f*1e5)/1e5;if(d===0){e="th";var h=a.call(this,g);h&&(g=h)}j.push("<"+e+(e=="th"?' scope="row"':"")+">"+g+"")},this),j.push("")},this),f.push(""),i=b.node(j.join("")),g=b.node('"),h=b.node('"),this.observe(g,"click",c.bind(this.spreadsheet.downloadCSV,this)).observe(h,"click",c.bind(this.spreadsheet.selectAllData,this));var k=b.node('
    ');b.insert(k,g),b.insert(k,h);var l=this.canvasHeight-b.size(this.spreadsheet.tabsContainer).height-2,m=b.node('
    ');return b.insert(m,k),b.insert(m,i),b.insert(this.el,m),this.spreadsheet.datagrid=i,this.spreadsheet.container=m,i},showTab:function(a){if(this.spreadsheet.activeTab===a)return;switch(a){case"graph":b.hide(this.spreadsheet.container),b.removeClass(this.spreadsheet.tabs.data,"selected"),b.addClass(this.spreadsheet.tabs.graph,"selected");break;case"data":this.spreadsheet.datagrid||this.spreadsheet.constructDataGrid(),b.show(this.spreadsheet.container),b.addClass(this.spreadsheet.tabs.data,"selected"),b.removeClass(this.spreadsheet.tabs.graph,"selected");break;default:throw"Illegal tab name: "+a}this.spreadsheet.activeTab=a},selectAllData:function(){if(this.spreadsheet.tabs){var a,b,c,d,e=this.spreadsheet.constructDataGrid();return this.spreadsheet.showTab("data"),setTimeout(function(){(c=e.ownerDocument)&&(d=c.defaultView)&&d.getSelection&&c.createRange&&(a=window.getSelection())&&a.removeAllRanges?(b=c.createRange(),b.selectNode(e),a.removeAllRanges(),a.addRange(b)):document.body&&document.body.createTextRange&&(b=document.body.createTextRange())&&(b.moveToElementText(e),b.select())},0),!0}return!1},downloadCSV:function(){var b="",d=this.series,e=this.options,f=this.spreadsheet.loadDataGrid(),g=encodeURIComponent(e.spreadsheet.csvFileSeparator);if(e.spreadsheet.decimalSeparator===e.spreadsheet.csvFileSeparator)throw"The decimal separator is the same as the column separator ("+e.spreadsheet.decimalSeparator+")";c.each(d,function(a,c){b+=g+'"'+(a.label||String.fromCharCode(65+c)).replace(/\"/g,'\\"')+'"'}),b+="%0D%0A",b+=c.reduce(f,function(b,c){var d=a.call(this,c[0])||"";d='"'+(d+"").replace(/\"/g,'\\"')+'"';var f=c.slice(1).join(g);return e.spreadsheet.decimalSeparator!=="."&&(f=f.replace(/\./g,e.spreadsheet.decimalSeparator)),b+d+g+f+"%0D%0A"},"",this),Flotr.isIE&&Flotr.isIE<9?(b=b.replace(new RegExp(g,"g"),decodeURIComponent(g)).replace(/%0A/g,"\n").replace(/%0D/g,"\r"),window.open().document.write(b)):window.open("data:text/csv,"+b)}})}(),function(){var a=Flotr.DOM;Flotr.addPlugin("titles",{callbacks:{"flotr:afterdraw":function(){this.titles.drawTitles()}},drawTitles:function(){var b,c=this.options,d=c.grid.labelMargin,e=this.ctx,f=this.axes;if(!c.HtmlText&&this.textEnabled){var g={size:c.fontSize,color:c.grid.color,textAlign:"center"};c.subtitle&&Flotr.drawText(e,c.subtitle,this.plotOffset.left+this.plotWidth/2,this.titleHeight+this.subtitleHeight-2,g),g.weight=1.5,g.size*=1.5,c.title&&Flotr.drawText(e,c.title,this.plotOffset.left+this.plotWidth/2,this.titleHeight-2,g),g.weight=1.8,g.size*=.8,f.x.options.title&&f.x.used&&(g.textAlign=f.x.options.titleAlign||"center",g.textBaseline="top",g.angle=Flotr.toRad(f.x.options.titleAngle),g=Flotr.getBestTextAlign(g.angle,g),Flotr.drawText(e,f.x.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+f.x.maxLabel.height+this.plotHeight+2*d,g)),f.x2.options.title&&f.x2.used&&(g.textAlign=f.x2.options.titleAlign||"center",g.textBaseline="bottom",g.angle=Flotr.toRad(f.x2.options.titleAngle),g=Flotr.getBestTextAlign(g.angle,g),Flotr.drawText(e,f.x2.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top-f.x2.maxLabel.height-2*d,g)),f.y.options.title&&f.y.used&&(g.textAlign=f.y.options.titleAlign||"right",g.textBaseline="middle",g.angle=Flotr.toRad(f.y.options.titleAngle),g=Flotr.getBestTextAlign(g.angle,g),Flotr.drawText(e,f.y.options.title,this.plotOffset.left-f.y.maxLabel.width-2*d,this.plotOffset.top+this.plotHeight/2,g)),f.y2.options.title&&f.y2.used&&(g.textAlign=f.y2.options.titleAlign||"left",g.textBaseline="middle",g.angle=Flotr.toRad(f.y2.options.titleAngle),g=Flotr.getBestTextAlign(g.angle,g),Flotr.drawText(e,f.y2.options.title,this.plotOffset.left+this.plotWidth+f.y2.maxLabel.width+2*d,this.plotOffset.top+this.plotHeight/2,g))}else{b=[],c.title&&b.push('
    ',c.title,"
    "),c.subtitle&&b.push('
    ',c.subtitle,"
    "),b.push(""),b.push('
    '),f.x.options.title&&f.x.used&&b.push('
    ',f.x.options.title,"
    "),f.x2.options.title&&f.x2.used&&b.push('
    ',f.x2.options.title,"
    "),f.y.options.title&&f.y.used&&b.push('
    ',f.y.options.title,"
    "),f.y2.options.title&&f.y2.used&&b.push('
    ',f.y2.options.title,"
    "),b=b.join("");var h=a.create("div");a.setStyles({color:c.grid.color}),h.className="flotr-titles",a.insert(this.el,h),a.insert(h,b)}}})}(); diff --git a/addons/web_graph/static/lib/flotr2/js/Axis.js b/addons/web_graph/static/lib/flotr2/js/Axis.js deleted file mode 100644 index 1c697309ef8..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/Axis.js +++ /dev/null @@ -1,303 +0,0 @@ -/** - * Flotr Axis Library - */ - -(function () { - -var - _ = Flotr._, - LOGARITHMIC = 'logarithmic'; - -function Axis (o) { - - this.orientation = 1; - this.offset = 0; - this.datamin = Number.MAX_VALUE; - this.datamax = -Number.MAX_VALUE; - - _.extend(this, o); - - this._setTranslations(); -} - - -// Prototype -Axis.prototype = { - - setScale : function () { - var length = this.length; - if (this.options.scaling == LOGARITHMIC) { - this.scale = length / (log(this.max, this.options.base) - log(this.min, this.options.base)); - } else { - this.scale = length / (this.max - this.min); - } - }, - - calculateTicks : function () { - var options = this.options; - - this.ticks = []; - this.minorTicks = []; - - // User Ticks - if(options.ticks){ - this._cleanUserTicks(options.ticks, this.ticks); - this._cleanUserTicks(options.minorTicks || [], this.minorTicks); - } - else { - if (options.mode == 'time') { - this._calculateTimeTicks(); - } else if (options.scaling === 'logarithmic') { - this._calculateLogTicks(); - } else { - this._calculateTicks(); - } - } - }, - - /** - * Calculates the range of an axis to apply autoscaling. - */ - calculateRange: function () { - - if (!this.used) return; - - var axis = this, - o = axis.options, - min = o.min !== null ? o.min : axis.datamin, - max = o.max !== null ? o.max : axis.datamax, - margin = o.autoscaleMargin; - - if (o.scaling == 'logarithmic') { - if (min <= 0) min = axis.datamin; - - // Let it widen later on - if (max <= 0) max = min; - } - - if (max == min) { - var widen = max ? 0.01 : 1.00; - if (o.min === null) min -= widen; - if (o.max === null) max += widen; - } - - if (o.scaling === 'logarithmic') { - if (min < 0) min = max / o.base; // Could be the result of widening - - var maxexp = Math.log(max); - if (o.base != Math.E) maxexp /= Math.log(o.base); - maxexp = Math.ceil(maxexp); - - var minexp = Math.log(min); - if (o.base != Math.E) minexp /= Math.log(o.base); - minexp = Math.ceil(minexp); - - axis.tickSize = Flotr.getTickSize(o.noTicks, minexp, maxexp, o.tickDecimals === null ? 0 : o.tickDecimals); - - // Try to determine a suitable amount of miniticks based on the length of a decade - if (o.minorTickFreq === null) { - if (maxexp - minexp > 10) - o.minorTickFreq = 0; - else if (maxexp - minexp > 5) - o.minorTickFreq = 2; - else - o.minorTickFreq = 5; - } - } else { - axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals); - } - - axis.min = min; - axis.max = max; //extendRange may use axis.min or axis.max, so it should be set before it is caled - - // Autoscaling. @todo This probably fails with log scale. Find a testcase and fix it - if(o.min === null && o.autoscale){ - axis.min -= axis.tickSize * margin; - // Make sure we don't go below zero if all values are positive. - if(axis.min < 0 && axis.datamin >= 0) axis.min = 0; - axis.min = axis.tickSize * Math.floor(axis.min / axis.tickSize); - } - - if(o.max === null && o.autoscale){ - axis.max += axis.tickSize * margin; - if(axis.max > 0 && axis.datamax <= 0 && axis.datamax != axis.datamin) axis.max = 0; - axis.max = axis.tickSize * Math.ceil(axis.max / axis.tickSize); - } - - if (axis.min == axis.max) axis.max = axis.min + 1; - }, - - calculateTextDimensions : function (T, options) { - - var maxLabel = '', - length, - i; - - if (this.options.showLabels) { - for (i = 0; i < this.ticks.length; ++i) { - length = this.ticks[i].label.length; - if (length > maxLabel.length){ - maxLabel = this.ticks[i].label; - } - } - } - - this.maxLabel = T.dimensions( - maxLabel, - {size:options.fontSize, angle: Flotr.toRad(this.options.labelsAngle)}, - 'font-size:smaller;', - 'flotr-grid-label' - ); - - this.titleSize = T.dimensions( - this.options.title, - {size:options.fontSize*1.2, angle: Flotr.toRad(this.options.titleAngle)}, - 'font-weight:bold;', - 'flotr-axis-title' - ); - }, - - _cleanUserTicks : function (ticks, axisTicks) { - - var axis = this, options = this.options, - v, i, label, tick; - - if(_.isFunction(ticks)) ticks = ticks({min : axis.min, max : axis.max}); - - for(i = 0; i < ticks.length; ++i){ - tick = ticks[i]; - if(typeof(tick) === 'object'){ - v = tick[0]; - label = (tick.length > 1) ? tick[1] : options.tickFormatter(v, {min : axis.min, max : axis.max}); - } else { - v = tick; - label = options.tickFormatter(v, {min : this.min, max : this.max}); - } - axisTicks[i] = { v: v, label: label }; - } - }, - - _calculateTimeTicks : function () { - this.ticks = Flotr.Date.generator(this); - }, - - _calculateLogTicks : function () { - - var axis = this, - o = axis.options, - v, - decadeStart; - - var max = Math.log(axis.max); - if (o.base != Math.E) max /= Math.log(o.base); - max = Math.ceil(max); - - var min = Math.log(axis.min); - if (o.base != Math.E) min /= Math.log(o.base); - min = Math.ceil(min); - - for (i = min; i < max; i += axis.tickSize) { - decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i); - // Next decade begins here: - var decadeEnd = decadeStart * ((o.base == Math.E) ? Math.exp(axis.tickSize) : Math.pow(o.base, axis.tickSize)); - var stepSize = (decadeEnd - decadeStart) / o.minorTickFreq; - - axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})}); - for (v = decadeStart + stepSize; v < decadeEnd; v += stepSize) - axis.minorTicks.push({v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max})}); - } - - // Always show the value at the would-be start of next decade (end of this decade) - decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i); - axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})}); - }, - - _calculateTicks : function () { - - var axis = this, - o = axis.options, - tickSize = axis.tickSize, - min = axis.min, - max = axis.max, - start = tickSize * Math.ceil(min / tickSize), // Round to nearest multiple of tick size. - decimals, - minorTickSize, - v, v2, - i, j; - - if (o.minorTickFreq) - minorTickSize = tickSize / o.minorTickFreq; - - // Then store all possible ticks. - for (i = 0; (v = v2 = start + i * tickSize) <= max; ++i){ - - // Round (this is always needed to fix numerical instability). - decimals = o.tickDecimals; - if (decimals === null) decimals = 1 - Math.floor(Math.log(tickSize) / Math.LN10); - if (decimals < 0) decimals = 0; - - v = v.toFixed(decimals); - axis.ticks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) }); - - if (o.minorTickFreq) { - for (j = 0; j < o.minorTickFreq && (i * tickSize + j * minorTickSize) < max; ++j) { - v = v2 + j * minorTickSize; - axis.minorTicks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) }); - } - } - } - - }, - - _setTranslations : function (logarithmic) { - this.d2p = (logarithmic ? d2pLog : d2p); - this.p2d = (logarithmic ? p2dLog : p2d); - } -}; - - -// Static Methods -_.extend(Axis, { - getAxes : function (options) { - return { - x: new Axis({options: options.xaxis, n: 1, length: this.plotWidth}), - x2: new Axis({options: options.x2axis, n: 2, length: this.plotWidth}), - y: new Axis({options: options.yaxis, n: 1, length: this.plotHeight, offset: this.plotHeight, orientation: -1}), - y2: new Axis({options: options.y2axis, n: 2, length: this.plotHeight, offset: this.plotHeight, orientation: -1}) - }; - } -}); - - -// Helper Methods - -function d2p (dataValue) { - return this.offset + this.orientation * (dataValue - this.min) * this.scale; -} - -function p2d (pointValue) { - return (this.offset + this.orientation * pointValue) / this.scale + this.min; -} - -function d2pLog (dataValue) { - return this.offset + this.orientation * (log(dataValue, this.options.base) - log(this.min, this.options.base)) * this.scale; -} - -function p2dLog (pointValue) { - return exp((this.offset + this.orientation * pointValue) / this.scale + log(this.min, this.options.base), this.options.base); -} - -function log (value, base) { - value = Math.log(Math.max(value, Number.MIN_VALUE)); - if (base !== Math.E) - value /= Math.log(base); - return value; -} - -function exp (value, base) { - return (base === Math.E) ? Math.exp(value) : Math.pow(base, value); -} - -Flotr.Axis = Axis; - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/Color.js b/addons/web_graph/static/lib/flotr2/js/Color.js deleted file mode 100644 index ab4ba0b432d..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/Color.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Flotr Color - */ - -(function () { - -var - _ = Flotr._; - -// Constructor -function Color (r, g, b, a) { - this.rgba = ['r','g','b','a']; - var x = 4; - while(-1<--x){ - this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0); - } - this.normalize(); -} - -// Constants -var COLOR_NAMES = { - aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255], - brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169], - darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47], - darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122], - darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130], - khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144], - lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255], - maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128], - violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0] -}; - -Color.prototype = { - scale: function(rf, gf, bf, af){ - var x = 4; - while (-1 < --x) { - if (!_.isUndefined(arguments[x])) this[this.rgba[x]] *= arguments[x]; - } - return this.normalize(); - }, - alpha: function(alpha) { - if (!_.isUndefined(alpha) && !_.isNull(alpha)) { - this.a = alpha; - } - return this.normalize(); - }, - clone: function(){ - return new Color(this.r, this.b, this.g, this.a); - }, - limit: function(val,minVal,maxVal){ - return Math.max(Math.min(val, maxVal), minVal); - }, - normalize: function(){ - var limit = this.limit; - this.r = limit(parseInt(this.r, 10), 0, 255); - this.g = limit(parseInt(this.g, 10), 0, 255); - this.b = limit(parseInt(this.b, 10), 0, 255); - this.a = limit(this.a, 0, 1); - return this; - }, - distance: function(color){ - if (!color) return; - color = new Color.parse(color); - var dist = 0, x = 3; - while(-1<--x){ - dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]); - } - return dist; - }, - toString: function(){ - return (this.a >= 1.0) ? 'rgb('+[this.r,this.g,this.b].join(',')+')' : 'rgba('+[this.r,this.g,this.b,this.a].join(',')+')'; - }, - contrast: function () { - var - test = 1 - ( 0.299 * this.r + 0.587 * this.g + 0.114 * this.b) / 255; - return (test < 0.5 ? '#000000' : '#ffffff'); - } -}; - -_.extend(Color, { - /** - * Parses a color string and returns a corresponding Color. - * The different tests are in order of probability to improve speed. - * @param {String, Color} str - string thats representing a color - * @return {Color} returns a Color object or false - */ - parse: function(color){ - if (color instanceof Color) return color; - - var result; - - // #a0b1c2 - if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))) - return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)); - - // rgb(num,num,num) - if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))) - return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10)); - - // #fff - if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))) - return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)); - - // rgba(num,num,num,num) - 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))) - return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10), parseFloat(result[4])); - - // rgb(num%,num%,num%) - if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))) - return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55); - - // rgba(num%,num%,num%,num) - 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))) - return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4])); - - // Otherwise, we're most likely dealing with a named color. - var name = (color+'').replace(/^\s*([\S\s]*?)\s*$/, '$1').toLowerCase(); - if(name == 'transparent'){ - return new Color(255, 255, 255, 0); - } - return (result = COLOR_NAMES[name]) ? new Color(result[0], result[1], result[2]) : new Color(0, 0, 0, 0); - }, - - /** - * Process color and options into color style. - */ - processColor: function(color, options) { - - var opacity = options.opacity; - if (!color) return 'rgba(0, 0, 0, 0)'; - if (color instanceof Color) return color.alpha(opacity).toString(); - if (_.isString(color)) return Color.parse(color).alpha(opacity).toString(); - - var grad = color.colors ? color : {colors: color}; - - if (!options.ctx) { - if (!_.isArray(grad.colors)) return 'rgba(0, 0, 0, 0)'; - return Color.parse(_.isArray(grad.colors[0]) ? grad.colors[0][1] : grad.colors[0]).alpha(opacity).toString(); - } - grad = _.extend({start: 'top', end: 'bottom'}, grad); - - if (/top/i.test(grad.start)) options.x1 = 0; - if (/left/i.test(grad.start)) options.y1 = 0; - if (/bottom/i.test(grad.end)) options.x2 = 0; - if (/right/i.test(grad.end)) options.y2 = 0; - - var i, c, stop, gradient = options.ctx.createLinearGradient(options.x1, options.y1, options.x2, options.y2); - for (i = 0; i < grad.colors.length; i++) { - c = grad.colors[i]; - if (_.isArray(c)) { - stop = c[0]; - c = c[1]; - } - else stop = i / (grad.colors.length-1); - gradient.addColorStop(stop, Color.parse(c).alpha(opacity)); - } - return gradient; - } -}); - -Flotr.Color = Color; - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/DOM.js b/addons/web_graph/static/lib/flotr2/js/DOM.js deleted file mode 100644 index 43df857395b..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/DOM.js +++ /dev/null @@ -1,88 +0,0 @@ -(function () { - -var _ = Flotr._; - -Flotr.DOM = { - addClass: function(element, name){ - var classList = (element.className ? element.className : ''); - if (_.include(classList.split(/\s+/g), name)) return; - element.className = (classList ? classList + ' ' : '') + name; - }, - /** - * Create an element. - */ - create: function(tag){ - return document.createElement(tag); - }, - node: function(html) { - var div = Flotr.DOM.create('div'), n; - div.innerHTML = html; - n = div.children[0]; - div.innerHTML = ''; - return n; - }, - /** - * Remove all children. - */ - empty: function(element){ - element.innerHTML = ''; - /* - if (!element) return; - _.each(element.childNodes, function (e) { - Flotr.DOM.empty(e); - element.removeChild(e); - }); - */ - }, - hide: function(element){ - Flotr.DOM.setStyles(element, {display:'none'}); - }, - /** - * Insert a child. - * @param {Element} element - * @param {Element|String} Element or string to be appended. - */ - insert: function(element, child){ - if(_.isString(child)) - element.innerHTML += child; - else if (_.isElement(child)) - element.appendChild(child); - }, - // @TODO find xbrowser implementation - opacity: function(element, opacity) { - element.style.opacity = opacity; - }, - position: function(element, p){ - if (!element.offsetParent) - return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)}; - - p = this.position(element.offsetParent); - p.left += element.offsetLeft; - p.top += element.offsetTop; - return p; - }, - removeClass: function(element, name) { - var classList = (element.className ? element.className : ''); - element.className = _.filter(classList.split(/\s+/g), function (c) { - if (c != name) return true; } - ).join(' '); - }, - setStyles: function(element, o) { - _.each(o, function (value, key) { - element.style[key] = value; - }); - }, - show: function(element){ - Flotr.DOM.setStyles(element, {display:''}); - }, - /** - * Return element size. - */ - size: function(element){ - return { - height : element.offsetHeight, - width : element.offsetWidth }; - } -}; - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/Date.js b/addons/web_graph/static/lib/flotr2/js/Date.js deleted file mode 100644 index fe72dba709f..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/Date.js +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Flotr Date - */ -Flotr.Date = { - - set : function (date, name, mode, value) { - mode = mode || 'UTC'; - name = 'set' + (mode === 'UTC' ? 'UTC' : '') + name; - date[name](value); - }, - - get : function (date, name, mode) { - mode = mode || 'UTC'; - name = 'get' + (mode === 'UTC' ? 'UTC' : '') + name; - return date[name](); - }, - - format: function(d, format, mode) { - if (!d) return; - - // We should maybe use an "official" date format spec, like PHP date() or ColdFusion - // http://fr.php.net/manual/en/function.date.php - // http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_c-d_29.html - var - get = this.get, - tokens = { - h: get(d, 'Hours', mode).toString(), - H: leftPad(get(d, 'Hours', mode)), - M: leftPad(get(d, 'Minutes', mode)), - S: leftPad(get(d, 'Seconds', mode)), - s: get(d, 'Milliseconds', mode), - d: get(d, 'Date', mode).toString(), - m: (get(d, 'Month') + 1).toString(), - y: get(d, 'FullYear').toString(), - b: Flotr.Date.monthNames[get(d, 'Month', mode)] - }; - - function leftPad(n){ - n += ''; - return n.length == 1 ? "0" + n : n; - } - - var r = [], c, - escape = false; - - for (var i = 0; i < format.length; ++i) { - c = format.charAt(i); - - if (escape) { - r.push(tokens[c] || c); - escape = false; - } - else if (c == "%") - escape = true; - else - r.push(c); - } - return r.join(''); - }, - getFormat: function(time, span) { - var tu = Flotr.Date.timeUnits; - if (time < tu.second) return "%h:%M:%S.%s"; - else if (time < tu.minute) return "%h:%M:%S"; - else if (time < tu.day) return (span < 2 * tu.day) ? "%h:%M" : "%b %d %h:%M"; - else if (time < tu.month) return "%b %d"; - else if (time < tu.year) return (span < tu.year) ? "%b" : "%b %y"; - else return "%y"; - }, - formatter: function (v, axis) { - var - options = axis.options, - scale = Flotr.Date.timeUnits[options.timeUnit], - d = new Date(v * scale); - - // first check global format - if (axis.options.timeFormat) - return Flotr.Date.format(d, options.timeFormat, options.timeMode); - - var span = (axis.max - axis.min) * scale, - t = axis.tickSize * Flotr.Date.timeUnits[axis.tickUnit]; - - return Flotr.Date.format(d, Flotr.Date.getFormat(t, span), options.timeMode); - }, - generator: function(axis) { - - var - set = this.set, - get = this.get, - timeUnits = this.timeUnits, - spec = this.spec, - options = axis.options, - mode = options.timeMode, - scale = timeUnits[options.timeUnit], - min = axis.min * scale, - max = axis.max * scale, - delta = (max - min) / options.noTicks, - ticks = [], - tickSize = axis.tickSize, - tickUnit, - formatter, i; - - // Use custom formatter or time tick formatter - formatter = (options.tickFormatter === Flotr.defaultTickFormatter ? - this.formatter : options.tickFormatter - ); - - for (i = 0; i < spec.length - 1; ++i) { - var d = spec[i][0] * timeUnits[spec[i][1]]; - if (delta < (d + spec[i+1][0] * timeUnits[spec[i+1][1]]) / 2 && d >= tickSize) - break; - } - tickSize = spec[i][0]; - tickUnit = spec[i][1]; - - // special-case the possibility of several years - if (tickUnit == "year") { - tickSize = Flotr.getTickSize(options.noTicks*timeUnits.year, min, max, 0); - - // Fix for 0.5 year case - if (tickSize == 0.5) { - tickUnit = "month"; - tickSize = 6; - } - } - - axis.tickUnit = tickUnit; - axis.tickSize = tickSize; - - var - d = new Date(min); - - var step = tickSize * timeUnits[tickUnit]; - - function setTick (name) { - set(d, name, mode, Flotr.floorInBase( - get(d, name, mode), tickSize - )); - } - - switch (tickUnit) { - case "millisecond": setTick('Milliseconds'); break; - case "second": setTick('Seconds'); break; - case "minute": setTick('Minutes'); break; - case "hour": setTick('Hours'); break; - case "month": setTick('Month'); break; - case "year": setTick('FullYear'); break; - } - - // reset smaller components - if (step >= timeUnits.second) set(d, 'Milliseconds', mode, 0); - if (step >= timeUnits.minute) set(d, 'Seconds', mode, 0); - if (step >= timeUnits.hour) set(d, 'Minutes', mode, 0); - if (step >= timeUnits.day) set(d, 'Hours', mode, 0); - if (step >= timeUnits.day * 4) set(d, 'Date', mode, 1); - if (step >= timeUnits.year) set(d, 'Month', mode, 0); - - var carry = 0, v = NaN, prev; - do { - prev = v; - v = d.getTime(); - ticks.push({ v: v / scale, label: formatter(v / scale, axis) }); - if (tickUnit == "month") { - if (tickSize < 1) { - /* a bit complicated - we'll divide the month up but we need to take care of fractions - so we don't end up in the middle of a day */ - set(d, 'Date', mode, 1); - var start = d.getTime(); - set(d, 'Month', mode, get(d, 'Month', mode) + 1) - var end = d.getTime(); - d.setTime(v + carry * timeUnits.hour + (end - start) * tickSize); - carry = get(d, 'Hours', mode) - set(d, 'Hours', mode, 0); - } - else - set(d, 'Month', mode, get(d, 'Month', mode) + tickSize); - } - else if (tickUnit == "year") { - set(d, 'FullYear', mode, get(d, 'FullYear', mode) + tickSize); - } - else - d.setTime(v + step); - - } while (v < max && v != prev); - - return ticks; - }, - timeUnits: { - millisecond: 1, - second: 1000, - minute: 1000 * 60, - hour: 1000 * 60 * 60, - day: 1000 * 60 * 60 * 24, - month: 1000 * 60 * 60 * 24 * 30, - year: 1000 * 60 * 60 * 24 * 365.2425 - }, - // the allowed tick sizes, after 1 year we use an integer algorithm - spec: [ - [1, "millisecond"], [20, "millisecond"], [50, "millisecond"], [100, "millisecond"], [200, "millisecond"], [500, "millisecond"], - [1, "second"], [2, "second"], [5, "second"], [10, "second"], [30, "second"], - [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], [30, "minute"], - [1, "hour"], [2, "hour"], [4, "hour"], [8, "hour"], [12, "hour"], - [1, "day"], [2, "day"], [3, "day"], - [0.25, "month"], [0.5, "month"], [1, "month"], [2, "month"], [3, "month"], [6, "month"], - [1, "year"] - ], - monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] -}; diff --git a/addons/web_graph/static/lib/flotr2/js/DefaultOptions.js b/addons/web_graph/static/lib/flotr2/js/DefaultOptions.js deleted file mode 100644 index 7399553df6a..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/DefaultOptions.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Flotr Defaults - */ -Flotr.defaultOptions = { - colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated. - ieBackgroundColor: '#FFFFFF', // Background color for excanvas clipping - title: null, // => The graph's title - subtitle: null, // => The graph's subtitle - shadowSize: 4, // => size of the 'fake' shadow - defaultType: null, // => default series type - HtmlText: true, // => wether to draw the text using HTML or on the canvas - fontColor: '#545454', // => default font color - fontSize: 7.5, // => canvas' text font size - resolution: 1, // => resolution of the graph, to have printer-friendly graphs ! - parseFloat: true, // => whether to preprocess data for floats (ie. if input is string) - xaxis: { - ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] - minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] - showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise - showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide - labelsAngle: 0, // => labels' angle, in degrees - title: null, // => axis title - titleAngle: 0, // => axis title's angle, in degrees - noTicks: 5, // => number of ticks for automagically generated ticks - minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks - tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string - tickDecimals: null, // => no. of decimals, null means auto - min: null, // => min. value to show, null means set automatically - max: null, // => max. value to show, null means set automatically - autoscale: false, // => Turns autoscaling on with true - autoscaleMargin: 0, // => margin in % to add if auto-setting min/max - color: null, // => color of the ticks - mode: 'normal', // => can be 'time' or 'normal' - timeFormat: null, - timeMode:'UTC', // => For UTC time ('local' for local time). - timeUnit:'millisecond',// => Unit for time (millisecond, second, minute, hour, day, month, year) - scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' - base: Math.E, - titleAlign: 'center', - margin: true // => Turn off margins with false - }, - x2axis: {}, - yaxis: { - ticks: null, // => format: either [1, 3] or [[1, 'a'], 3] - minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3] - showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise - showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide - labelsAngle: 0, // => labels' angle, in degrees - title: null, // => axis title - titleAngle: 90, // => axis title's angle, in degrees - noTicks: 5, // => number of ticks for automagically generated ticks - minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks - tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string - tickDecimals: null, // => no. of decimals, null means auto - min: null, // => min. value to show, null means set automatically - max: null, // => max. value to show, null means set automatically - autoscale: false, // => Turns autoscaling on with true - autoscaleMargin: 0, // => margin in % to add if auto-setting min/max - color: null, // => The color of the ticks - scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic' - base: Math.E, - titleAlign: 'center', - margin: true // => Turn off margins with false - }, - y2axis: { - titleAngle: 270 - }, - grid: { - color: '#545454', // => primary color used for outline and labels - backgroundColor: null, // => null for transparent, else color - backgroundImage: null, // => background image. String or object with src, left and top - watermarkAlpha: 0.4, // => - tickColor: '#DDDDDD', // => color used for the ticks - labelMargin: 3, // => margin in pixels - verticalLines: true, // => whether to show gridlines in vertical direction - minorVerticalLines: null, // => whether to show gridlines for minor ticks in vertical dir. - horizontalLines: true, // => whether to show gridlines in horizontal direction - minorHorizontalLines: null, // => whether to show gridlines for minor ticks in horizontal dir. - outlineWidth: 1, // => width of the grid outline/border in pixels - outline : 'nsew', // => walls of the outline to display - circular: false // => if set to true, the grid will be circular, must be used when radars are drawn - }, - mouse: { - track: false, // => true to track the mouse, no tracking otherwise - trackAll: false, - position: 'se', // => position of the value box (default south-east) - relative: false, // => next to the mouse cursor - trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box - margin: 5, // => margin in pixels of the valuebox - lineColor: '#FF3F19', // => line color of points that are drawn when mouse comes near a value of a series - trackDecimals: 1, // => decimals for the track values - sensibility: 2, // => the lower this number, the more precise you have to aim to show a value - trackY: true, // => whether or not to track the mouse in the y axis - radius: 3, // => radius of the track point - fillColor: null, // => color to fill our select bar with only applies to bar and similar graphs (only bars for now) - fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - } -}; diff --git a/addons/web_graph/static/lib/flotr2/js/EventAdapter.js b/addons/web_graph/static/lib/flotr2/js/EventAdapter.js deleted file mode 100644 index 062ceeab294..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/EventAdapter.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Flotr Event Adapter - */ -(function () { -var - F = Flotr, - bean = F.bean; -F.EventAdapter = { - observe: function(object, name, callback) { - bean.add(object, name, callback); - return this; - }, - fire: function(object, name, args) { - bean.fire(object, name, args); - if (typeof(Prototype) != 'undefined') - Event.fire(object, name, args); - // @TODO Someone who uses mootools, add mootools adapter for existing applciations. - return this; - }, - stopObserving: function(object, name, callback) { - bean.remove(object, name, callback); - return this; - }, - eventPointer: function(e) { - if (!F._.isUndefined(e.touches) && e.touches.length > 0) { - return { - x : e.touches[0].pageX, - y : e.touches[0].pageY - }; - } else if (!F._.isUndefined(e.changedTouches) && e.changedTouches.length > 0) { - return { - x : e.changedTouches[0].pageX, - y : e.changedTouches[0].pageY - }; - } else if (e.pageX || e.pageY) { - return { - x : e.pageX, - y : e.pageY - }; - } else if (e.clientX || e.clientY) { - var - d = document, - b = d.body, - de = d.documentElement; - return { - x: e.clientX + b.scrollLeft + de.scrollLeft, - y: e.clientY + b.scrollTop + de.scrollTop - }; - } - } -}; -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/Flotr.js b/addons/web_graph/static/lib/flotr2/js/Flotr.js deleted file mode 100644 index e8256096adb..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/Flotr.js +++ /dev/null @@ -1,250 +0,0 @@ -/** - * Flotr2 (c) 2012 Carl Sutherland - * MIT License - * Special thanks to: - * Flotr: http://code.google.com/p/flotr/ (fork) - * Flot: https://github.com/flot/flot (original fork) - */ -(function () { - -var - global = this, - previousFlotr = this.Flotr, - Flotr; - -Flotr = { - _: _, - bean: bean, - isIphone: /iphone/i.test(navigator.userAgent), - isIE: (navigator.appVersion.indexOf("MSIE") != -1 ? parseFloat(navigator.appVersion.split("MSIE")[1]) : false), - - /** - * An object of the registered graph types. Use Flotr.addType(type, object) - * to add your own type. - */ - graphTypes: {}, - - /** - * The list of the registered plugins - */ - plugins: {}, - - /** - * Can be used to add your own chart type. - * @param {String} name - Type of chart, like 'pies', 'bars' etc. - * @param {String} graphType - The object containing the basic drawing functions (draw, etc) - */ - addType: function(name, graphType){ - Flotr.graphTypes[name] = graphType; - Flotr.defaultOptions[name] = graphType.options || {}; - Flotr.defaultOptions.defaultType = Flotr.defaultOptions.defaultType || name; - }, - - /** - * Can be used to add a plugin - * @param {String} name - The name of the plugin - * @param {String} plugin - The object containing the plugin's data (callbacks, options, function1, function2, ...) - */ - addPlugin: function(name, plugin){ - Flotr.plugins[name] = plugin; - Flotr.defaultOptions[name] = plugin.options || {}; - }, - - /** - * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha. - * You could also draw graphs by directly calling Flotr.Graph(element, data, options). - * @param {Element} el - element to insert the graph into - * @param {Object} data - an array or object of dataseries - * @param {Object} options - an object containing options - * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph - * @return {Object} returns a new graph object and of course draws the graph. - */ - draw: function(el, data, options, GraphKlass){ - GraphKlass = GraphKlass || Flotr.Graph; - return new GraphKlass(el, data, options); - }, - - /** - * Recursively merges two objects. - * @param {Object} src - source object (likely the object with the least properties) - * @param {Object} dest - destination object (optional, object with the most properties) - * @return {Object} recursively merged Object - * @TODO See if we can't remove this. - */ - merge: function(src, dest){ - var i, v, result = dest || {}; - - for (i in src) { - v = src[i]; - if (v && typeof(v) === 'object') { - if (v.constructor === Array) { - result[i] = this._.clone(v); - } else if (v.constructor !== RegExp && !this._.isElement(v)) { - result[i] = Flotr.merge(v, (dest ? dest[i] : undefined)); - } else { - result[i] = v; - } - } else { - result[i] = v; - } - } - - return result; - }, - - /** - * Recursively clones an object. - * @param {Object} object - The object to clone - * @return {Object} the clone - * @TODO See if we can't remove this. - */ - clone: function(object){ - return Flotr.merge(object, {}); - }, - - /** - * Function calculates the ticksize and returns it. - * @param {Integer} noTicks - number of ticks - * @param {Integer} min - lower bound integer value for the current axis - * @param {Integer} max - upper bound integer value for the current axis - * @param {Integer} decimals - number of decimals for the ticks - * @return {Integer} returns the ticksize in pixels - */ - getTickSize: function(noTicks, min, max, decimals){ - var delta = (max - min) / noTicks, - magn = Flotr.getMagnitude(delta), - tickSize = 10, - norm = delta / magn; // Norm is between 1.0 and 10.0. - - if(norm < 1.5) tickSize = 1; - else if(norm < 2.25) tickSize = 2; - else if(norm < 3) tickSize = ((decimals === 0) ? 2 : 2.5); - else if(norm < 7.5) tickSize = 5; - - return tickSize * magn; - }, - - /** - * Default tick formatter. - * @param {String, Integer} val - tick value integer - * @param {Object} axisOpts - the axis' options - * @return {String} formatted tick string - */ - defaultTickFormatter: function(val, axisOpts){ - return val+''; - }, - - /** - * Formats the mouse tracker values. - * @param {Object} obj - Track value Object {x:..,y:..} - * @return {String} Formatted track string - */ - defaultTrackFormatter: function(obj){ - return '('+obj.x+', '+obj.y+')'; - }, - - /** - * Utility function to convert file size values in bytes to kB, MB, ... - * @param value {Number} - The value to convert - * @param precision {Number} - The number of digits after the comma (default: 2) - * @param base {Number} - The base (default: 1000) - */ - engineeringNotation: function(value, precision, base){ - var sizes = ['Y','Z','E','P','T','G','M','k',''], - fractionSizes = ['y','z','a','f','p','n','µ','m',''], - total = sizes.length; - - base = base || 1000; - precision = Math.pow(10, precision || 2); - - if (value === 0) return 0; - - if (value > 1) { - while (total-- && (value >= base)) value /= base; - } - else { - sizes = fractionSizes; - total = sizes.length; - while (total-- && (value < 1)) value *= base; - } - - return (Math.round(value * precision) / precision) + sizes[total]; - }, - - /** - * Returns the magnitude of the input value. - * @param {Integer, Float} x - integer or float value - * @return {Integer, Float} returns the magnitude of the input value - */ - getMagnitude: function(x){ - return Math.pow(10, Math.floor(Math.log(x) / Math.LN10)); - }, - toPixel: function(val){ - return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val); - }, - toRad: function(angle){ - return -angle * (Math.PI/180); - }, - floorInBase: function(n, base) { - return base * Math.floor(n / base); - }, - drawText: function(ctx, text, x, y, style) { - if (!ctx.fillText) { - ctx.drawText(text, x, y, style); - return; - } - - style = this._.extend({ - size: Flotr.defaultOptions.fontSize, - color: '#000000', - textAlign: 'left', - textBaseline: 'bottom', - weight: 1, - angle: 0 - }, style); - - ctx.save(); - ctx.translate(x, y); - ctx.rotate(style.angle); - ctx.fillStyle = style.color; - ctx.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif"; - ctx.textAlign = style.textAlign; - ctx.textBaseline = style.textBaseline; - ctx.fillText(text, 0, 0); - ctx.restore(); - }, - getBestTextAlign: function(angle, style) { - style = style || {textAlign: 'center', textBaseline: 'middle'}; - angle += Flotr.getTextAngleFromAlign(style); - - if (Math.abs(Math.cos(angle)) > 10e-3) - style.textAlign = (Math.cos(angle) > 0 ? 'right' : 'left'); - - if (Math.abs(Math.sin(angle)) > 10e-3) - style.textBaseline = (Math.sin(angle) > 0 ? 'top' : 'bottom'); - - return style; - }, - alignTable: { - 'right middle' : 0, - 'right top' : Math.PI/4, - 'center top' : Math.PI/2, - 'left top' : 3*(Math.PI/4), - 'left middle' : Math.PI, - 'left bottom' : -3*(Math.PI/4), - 'center bottom': -Math.PI/2, - 'right bottom' : -Math.PI/4, - 'center middle': 0 - }, - getTextAngleFromAlign: function(style) { - return Flotr.alignTable[style.textAlign+' '+style.textBaseline] || 0; - }, - noConflict : function () { - global.Flotr = previousFlotr; - return this; - } -}; - -global.Flotr = Flotr; - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/Graph.js b/addons/web_graph/static/lib/flotr2/js/Graph.js deleted file mode 100644 index 0e0310a5f4e..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/Graph.js +++ /dev/null @@ -1,745 +0,0 @@ -/** - * Flotr Graph class that plots a graph on creation. - */ -(function () { - -var - D = Flotr.DOM, - E = Flotr.EventAdapter, - _ = Flotr._, - flotr = Flotr; -/** - * Flotr Graph constructor. - * @param {Element} el - element to insert the graph into - * @param {Object} data - an array or object of dataseries - * @param {Object} options - an object containing options - */ -Graph = function(el, data, options){ -// Let's see if we can get away with out this [JS] -// try { - this._setEl(el); - this._initMembers(); - this._initPlugins(); - - E.fire(this.el, 'flotr:beforeinit', [this]); - - this.data = data; - this.series = flotr.Series.getSeries(data); - this._initOptions(options); - this._initGraphTypes(); - this._initCanvas(); - this._text = new flotr.Text({ - element : this.el, - ctx : this.ctx, - html : this.options.HtmlText, - textEnabled : this.textEnabled - }); - E.fire(this.el, 'flotr:afterconstruct', [this]); - this._initEvents(); - - this.findDataRanges(); - this.calculateSpacing(); - - this.draw(_.bind(function() { - E.fire(this.el, 'flotr:afterinit', [this]); - }, this)); -/* - try { - } catch (e) { - try { - console.error(e); - } catch (e2) {} - }*/ -}; - -function observe (object, name, callback) { - E.observe.apply(this, arguments); - this._handles.push(arguments); - return this; -} - -Graph.prototype = { - - destroy: function () { - E.fire(this.el, 'flotr:destroy'); - _.each(this._handles, function (handle) { - E.stopObserving.apply(this, handle); - }); - this._handles = []; - this.el.graph = null; - }, - - observe : observe, - - /** - * @deprecated - */ - _observe : observe, - - processColor: function(color, options){ - var o = { x1: 0, y1: 0, x2: this.plotWidth, y2: this.plotHeight, opacity: 1, ctx: this.ctx }; - _.extend(o, options); - return flotr.Color.processColor(color, o); - }, - /** - * Function determines the min and max values for the xaxis and yaxis. - * - * TODO logarithmic range validation (consideration of 0) - */ - findDataRanges: function(){ - var a = this.axes, - xaxis, yaxis, range; - - _.each(this.series, function (series) { - range = series.getRange(); - if (range) { - xaxis = series.xaxis; - yaxis = series.yaxis; - xaxis.datamin = Math.min(range.xmin, xaxis.datamin); - xaxis.datamax = Math.max(range.xmax, xaxis.datamax); - yaxis.datamin = Math.min(range.ymin, yaxis.datamin); - yaxis.datamax = Math.max(range.ymax, yaxis.datamax); - xaxis.used = (xaxis.used || range.xused); - yaxis.used = (yaxis.used || range.yused); - } - }, this); - - // Check for empty data, no data case (none used) - if (!a.x.used && !a.x2.used) a.x.used = true; - if (!a.y.used && !a.y2.used) a.y.used = true; - - _.each(a, function (axis) { - axis.calculateRange(); - }); - - var - types = _.keys(flotr.graphTypes), - drawn = false; - - _.each(this.series, function (series) { - if (series.hide) return; - _.each(types, function (type) { - if (series[type] && series[type].show) { - this.extendRange(type, series); - drawn = true; - } - }, this); - if (!drawn) { - this.extendRange(this.options.defaultType, series); - } - }, this); - }, - - extendRange : function (type, series) { - if (this[type].extendRange) this[type].extendRange(series, series.data, series[type], this[type]); - if (this[type].extendYRange) this[type].extendYRange(series.yaxis, series.data, series[type], this[type]); - if (this[type].extendXRange) this[type].extendXRange(series.xaxis, series.data, series[type], this[type]); - }, - - /** - * Calculates axis label sizes. - */ - calculateSpacing: function(){ - - var a = this.axes, - options = this.options, - series = this.series, - margin = options.grid.labelMargin, - T = this._text, - x = a.x, - x2 = a.x2, - y = a.y, - y2 = a.y2, - maxOutset = options.grid.outlineWidth, - i, j, l, dim; - - // TODO post refactor, fix this - _.each(a, function (axis) { - axis.calculateTicks(); - axis.calculateTextDimensions(T, options); - }); - - // Title height - dim = T.dimensions( - options.title, - {size: options.fontSize*1.5}, - 'font-size:1em;font-weight:bold;', - 'flotr-title' - ); - this.titleHeight = dim.height; - - // Subtitle height - dim = T.dimensions( - options.subtitle, - {size: options.fontSize}, - 'font-size:smaller;', - 'flotr-subtitle' - ); - this.subtitleHeight = dim.height; - - for(j = 0; j < options.length; ++j){ - if (series[j].points.show){ - maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2); - } - } - - var p = this.plotOffset; - if (x.options.margin === false) { - p.bottom = 0; - p.top = 0; - } else { - p.bottom += (options.grid.circular ? 0 : (x.used && x.options.showLabels ? (x.maxLabel.height + margin) : 0)) + - (x.used && x.options.title ? (x.titleSize.height + margin) : 0) + maxOutset; - - p.top += (options.grid.circular ? 0 : (x2.used && x2.options.showLabels ? (x2.maxLabel.height + margin) : 0)) + - (x2.used && x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight + maxOutset; - } - if (y.options.margin === false) { - p.left = 0; - p.right = 0; - } else { - p.left += (options.grid.circular ? 0 : (y.used && y.options.showLabels ? (y.maxLabel.width + margin) : 0)) + - (y.used && y.options.title ? (y.titleSize.width + margin) : 0) + maxOutset; - - p.right += (options.grid.circular ? 0 : (y2.used && y2.options.showLabels ? (y2.maxLabel.width + margin) : 0)) + - (y2.used && y2.options.title ? (y2.titleSize.width + margin) : 0) + maxOutset; - } - - p.top = Math.floor(p.top); // In order the outline not to be blured - - this.plotWidth = this.canvasWidth - p.left - p.right; - this.plotHeight = this.canvasHeight - p.bottom - p.top; - - // TODO post refactor, fix this - x.length = x2.length = this.plotWidth; - y.length = y2.length = this.plotHeight; - y.offset = y2.offset = this.plotHeight; - x.setScale(); - x2.setScale(); - y.setScale(); - y2.setScale(); - }, - /** - * Draws grid, labels, series and outline. - */ - draw: function(after) { - - var - context = this.ctx, - i; - - E.fire(this.el, 'flotr:beforedraw', [this.series, this]); - - if (this.series.length) { - - context.save(); - context.translate(this.plotOffset.left, this.plotOffset.top); - - for (i = 0; i < this.series.length; i++) { - if (!this.series[i].hide) this.drawSeries(this.series[i]); - } - - context.restore(); - this.clip(); - } - - E.fire(this.el, 'flotr:afterdraw', [this.series, this]); - if (after) after(); - }, - /** - * Actually draws the graph. - * @param {Object} series - series to draw - */ - drawSeries: function(series){ - - function drawChart (series, typeKey) { - var options = this.getOptions(series, typeKey); - this[typeKey].draw(options); - } - - var drawn = false; - series = series || this.series; - - _.each(flotr.graphTypes, function (type, typeKey) { - if (series[typeKey] && series[typeKey].show && this[typeKey]) { - drawn = true; - drawChart.call(this, series, typeKey); - } - }, this); - - if (!drawn) drawChart.call(this, series, this.options.defaultType); - }, - - getOptions : function (series, typeKey) { - var - type = series[typeKey], - graphType = this[typeKey], - options = { - context : this.ctx, - width : this.plotWidth, - height : this.plotHeight, - fontSize : this.options.fontSize, - fontColor : this.options.fontColor, - textEnabled : this.textEnabled, - htmlText : this.options.HtmlText, - text : this._text, // TODO Is this necessary? - element : this.el, - data : series.data, - color : series.color, - shadowSize : series.shadowSize, - xScale : _.bind(series.xaxis.d2p, series.xaxis), - yScale : _.bind(series.yaxis.d2p, series.yaxis) - }; - - options = flotr.merge(type, options); - - // Fill - options.fillStyle = this.processColor( - type.fillColor || series.color, - {opacity: type.fillOpacity} - ); - - return options; - }, - /** - * Calculates the coordinates from a mouse event object. - * @param {Event} event - Mouse Event object. - * @return {Object} Object with coordinates of the mouse. - */ - getEventPosition: function (e){ - - var - d = document, - b = d.body, - de = d.documentElement, - axes = this.axes, - plotOffset = this.plotOffset, - lastMousePos = this.lastMousePos, - pointer = E.eventPointer(e), - dx = pointer.x - lastMousePos.pageX, - dy = pointer.y - lastMousePos.pageY, - r, rx, ry; - - if ('ontouchstart' in this.el) { - r = D.position(this.overlay); - rx = pointer.x - r.left - plotOffset.left; - ry = pointer.y - r.top - plotOffset.top; - } else { - r = this.overlay.getBoundingClientRect(); - rx = e.clientX - r.left - plotOffset.left - b.scrollLeft - de.scrollLeft; - ry = e.clientY - r.top - plotOffset.top - b.scrollTop - de.scrollTop; - } - - return { - x: axes.x.p2d(rx), - x2: axes.x2.p2d(rx), - y: axes.y.p2d(ry), - y2: axes.y2.p2d(ry), - relX: rx, - relY: ry, - dX: dx, - dY: dy, - absX: pointer.x, - absY: pointer.y, - pageX: pointer.x, - pageY: pointer.y - }; - }, - /** - * Observes the 'click' event and fires the 'flotr:click' event. - * @param {Event} event - 'click' Event object. - */ - clickHandler: function(event){ - if(this.ignoreClick){ - this.ignoreClick = false; - return this.ignoreClick; - } - E.fire(this.el, 'flotr:click', [this.getEventPosition(event), this]); - }, - /** - * Observes mouse movement over the graph area. Fires the 'flotr:mousemove' event. - * @param {Event} event - 'mousemove' Event object. - */ - mouseMoveHandler: function(event){ - if (this.mouseDownMoveHandler) return; - var pos = this.getEventPosition(event); - E.fire(this.el, 'flotr:mousemove', [event, pos, this]); - this.lastMousePos = pos; - }, - /** - * Observes the 'mousedown' event. - * @param {Event} event - 'mousedown' Event object. - */ - mouseDownHandler: function (event){ - - /* - // @TODO Context menu? - if(event.isRightClick()) { - event.stop(); - - var overlay = this.overlay; - overlay.hide(); - - function cancelContextMenu () { - overlay.show(); - E.stopObserving(document, 'mousemove', cancelContextMenu); - } - E.observe(document, 'mousemove', cancelContextMenu); - return; - } - */ - - if (this.mouseUpHandler) return; - this.mouseUpHandler = _.bind(function (e) { - E.stopObserving(document, 'mouseup', this.mouseUpHandler); - E.stopObserving(document, 'mousemove', this.mouseDownMoveHandler); - this.mouseDownMoveHandler = null; - this.mouseUpHandler = null; - // @TODO why? - //e.stop(); - E.fire(this.el, 'flotr:mouseup', [e, this]); - }, this); - this.mouseDownMoveHandler = _.bind(function (e) { - var pos = this.getEventPosition(e); - E.fire(this.el, 'flotr:mousemove', [event, pos, this]); - this.lastMousePos = pos; - }, this); - E.observe(document, 'mouseup', this.mouseUpHandler); - E.observe(document, 'mousemove', this.mouseDownMoveHandler); - E.fire(this.el, 'flotr:mousedown', [event, this]); - this.ignoreClick = false; - }, - drawTooltip: function(content, x, y, options) { - var mt = this.getMouseTrack(), - 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;', - p = options.position, - m = options.margin, - plotOffset = this.plotOffset; - - if(x !== null && y !== null){ - if (!options.relative) { // absolute to the canvas - if(p.charAt(0) == 'n') style += 'top:' + (m + plotOffset.top) + 'px;bottom:auto;'; - else if(p.charAt(0) == 's') style += 'bottom:' + (m + plotOffset.bottom) + 'px;top:auto;'; - if(p.charAt(1) == 'e') style += 'right:' + (m + plotOffset.right) + 'px;left:auto;'; - else if(p.charAt(1) == 'w') style += 'left:' + (m + plotOffset.left) + 'px;right:auto;'; - } - else { // relative to the mouse - if(p.charAt(0) == 'n') style += 'bottom:' + (m - plotOffset.top - y + this.canvasHeight) + 'px;top:auto;'; - else if(p.charAt(0) == 's') style += 'top:' + (m + plotOffset.top + y) + 'px;bottom:auto;'; - if(p.charAt(1) == 'e') style += 'left:' + (m + plotOffset.left + x) + 'px;right:auto;'; - else if(p.charAt(1) == 'w') style += 'right:' + (m - plotOffset.left - x + this.canvasWidth) + 'px;left:auto;'; - } - - mt.style.cssText = style; - D.empty(mt); - D.insert(mt, content); - D.show(mt); - } - else { - D.hide(mt); - } - }, - - clip: function () { - - var - ctx = this.ctx, - o = this.plotOffset, - w = this.canvasWidth, - h = this.canvasHeight; - - if (flotr.isIE && flotr.isIE < 9) { - // Clipping for excanvas :-( - ctx.save(); - ctx.fillStyle = this.processColor(this.options.ieBackgroundColor); - ctx.fillRect(0, 0, w, o.top); - ctx.fillRect(0, 0, o.left, h); - ctx.fillRect(0, h - o.bottom, w, o.bottom); - ctx.fillRect(w - o.right, 0, o.right,h); - ctx.restore(); - } else { - ctx.clearRect(0, 0, w, o.top); - ctx.clearRect(0, 0, o.left, h); - ctx.clearRect(0, h - o.bottom, w, o.bottom); - ctx.clearRect(w - o.right, 0, o.right,h); - } - }, - - _initMembers: function() { - this._handles = []; - this.lastMousePos = {pageX: null, pageY: null }; - this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0}; - this.ignoreClick = true; - this.prevHit = null; - }, - - _initGraphTypes: function() { - _.each(flotr.graphTypes, function(handler, graphType){ - this[graphType] = flotr.clone(handler); - }, this); - }, - - _initEvents: function () { - - var - el = this.el, - touchendHandler, movement, touchend; - - if ('ontouchstart' in el) { - - touchendHandler = _.bind(function (e) { - touchend = true; - E.stopObserving(document, 'touchend', touchendHandler); - E.fire(el, 'flotr:mouseup', [event, this]); - this.multitouches = null; - - if (!movement) { - this.clickHandler(e); - } - }, this); - - this.observe(this.overlay, 'touchstart', _.bind(function (e) { - movement = false; - touchend = false; - this.ignoreClick = false; - - if (e.touches && e.touches.length > 1) { - this.multitouches = e.touches; - } - - E.fire(el, 'flotr:mousedown', [event, this]); - this.observe(document, 'touchend', touchendHandler); - }, this)); - - this.observe(this.overlay, 'touchmove', _.bind(function (e) { - - var pos = this.getEventPosition(e); - - e.preventDefault(); - - movement = true; - - if (this.multitouches || (e.touches && e.touches.length > 1)) { - this.multitouches = e.touches; - } else { - if (!touchend) { - E.fire(el, 'flotr:mousemove', [event, pos, this]); - } - } - this.lastMousePos = pos; - }, this)); - - } else { - this. - observe(this.overlay, 'mousedown', _.bind(this.mouseDownHandler, this)). - observe(el, 'mousemove', _.bind(this.mouseMoveHandler, this)). - observe(this.overlay, 'click', _.bind(this.clickHandler, this)). - observe(el, 'mouseout', function () { - E.fire(el, 'flotr:mouseout'); - }); - } - }, - - /** - * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use - * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements - * are created, the elements are inserted into the container element. - */ - _initCanvas: function(){ - var el = this.el, - o = this.options, - children = el.children, - removedChildren = [], - child, i, - size, style; - - // Empty the el - for (i = children.length; i--;) { - child = children[i]; - if (!this.canvas && child.className === 'flotr-canvas') { - this.canvas = child; - } else if (!this.overlay && child.className === 'flotr-overlay') { - this.overlay = child; - } else { - removedChildren.push(child); - } - } - for (i = removedChildren.length; i--;) { - el.removeChild(removedChildren[i]); - } - - D.setStyles(el, {position: 'relative'}); // For positioning labels and overlay. - size = {}; - size.width = el.clientWidth; - size.height = el.clientHeight; - - if(size.width <= 0 || size.height <= 0 || o.resolution <= 0){ - throw 'Invalid dimensions for plot, width = ' + size.width + ', height = ' + size.height + ', resolution = ' + o.resolution; - } - - // Main canvas for drawing graph types - this.canvas = getCanvas(this.canvas, 'canvas'); - // Overlay canvas for interactive features - this.overlay = getCanvas(this.overlay, 'overlay'); - this.ctx = getContext(this.canvas); - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); - this.octx = getContext(this.overlay); - this.octx.clearRect(0, 0, this.overlay.width, this.overlay.height); - this.canvasHeight = size.height; - this.canvasWidth = size.width; - this.textEnabled = !!this.ctx.drawText || !!this.ctx.fillText; // Enable text functions - - function getCanvas(canvas, name){ - if(!canvas){ - canvas = D.create('canvas'); - if (typeof FlashCanvas != "undefined" && typeof canvas.getContext === 'function') { - FlashCanvas.initElement(canvas); - } - canvas.className = 'flotr-'+name; - canvas.style.cssText = 'position:absolute;left:0px;top:0px;'; - D.insert(el, canvas); - } - _.each(size, function(size, attribute){ - D.show(canvas); - if (name == 'canvas' && canvas.getAttribute(attribute) === size) { - return; - } - canvas.setAttribute(attribute, size * o.resolution); - canvas.style[attribute] = size + 'px'; - }); - canvas.context_ = null; // Reset the ExCanvas context - return canvas; - } - - function getContext(canvas){ - if(window.G_vmlCanvasManager) window.G_vmlCanvasManager.initElement(canvas); // For ExCanvas - var context = canvas.getContext('2d'); - if(!window.G_vmlCanvasManager) context.scale(o.resolution, o.resolution); - return context; - } - }, - - _initPlugins: function(){ - // TODO Should be moved to flotr and mixed in. - _.each(flotr.plugins, function(plugin, name){ - _.each(plugin.callbacks, function(fn, c){ - this.observe(this.el, c, _.bind(fn, this)); - }, this); - this[name] = flotr.clone(plugin); - _.each(this[name], function(fn, p){ - if (_.isFunction(fn)) - this[name][p] = _.bind(fn, this); - }, this); - }, this); - }, - - /** - * Sets options and initializes some variables and color specific values, used by the constructor. - * @param {Object} opts - options object - */ - _initOptions: function(opts){ - var options = flotr.clone(flotr.defaultOptions); - options.x2axis = _.extend(_.clone(options.xaxis), options.x2axis); - options.y2axis = _.extend(_.clone(options.yaxis), options.y2axis); - this.options = flotr.merge(opts || {}, options); - - if (this.options.grid.minorVerticalLines === null && - this.options.xaxis.scaling === 'logarithmic') { - this.options.grid.minorVerticalLines = true; - } - if (this.options.grid.minorHorizontalLines === null && - this.options.yaxis.scaling === 'logarithmic') { - this.options.grid.minorHorizontalLines = true; - } - - E.fire(this.el, 'flotr:afterinitoptions', [this]); - - this.axes = flotr.Axis.getAxes(this.options); - - // Initialize some variables used throughout this function. - var assignedColors = [], - colors = [], - ln = this.series.length, - neededColors = this.series.length, - oc = this.options.colors, - usedColors = [], - variation = 0, - c, i, j, s; - - // Collect user-defined colors from series. - for(i = neededColors - 1; i > -1; --i){ - c = this.series[i].color; - if(c){ - --neededColors; - if(_.isNumber(c)) assignedColors.push(c); - else usedColors.push(flotr.Color.parse(c)); - } - } - - // Calculate the number of colors that need to be generated. - for(i = assignedColors.length - 1; i > -1; --i) - neededColors = Math.max(neededColors, assignedColors[i] + 1); - - // Generate needed number of colors. - for(i = 0; colors.length < neededColors;){ - c = (oc.length == i) ? new flotr.Color(100, 100, 100) : flotr.Color.parse(oc[i]); - - // Make sure each serie gets a different color. - var sign = variation % 2 == 1 ? -1 : 1, - factor = 1 + sign * Math.ceil(variation / 2) * 0.2; - c.scale(factor, factor, factor); - - /** - * @todo if we're getting too close to something else, we should probably skip this one - */ - colors.push(c); - - if(++i >= oc.length){ - i = 0; - ++variation; - } - } - - // Fill the options with the generated colors. - for(i = 0, j = 0; i < ln; ++i){ - s = this.series[i]; - - // Assign the color. - if (!s.color){ - s.color = colors[j++].toString(); - }else if(_.isNumber(s.color)){ - s.color = colors[s.color].toString(); - } - - // Every series needs an axis - if (!s.xaxis) s.xaxis = this.axes.x; - if (s.xaxis == 1) s.xaxis = this.axes.x; - else if (s.xaxis == 2) s.xaxis = this.axes.x2; - - if (!s.yaxis) s.yaxis = this.axes.y; - if (s.yaxis == 1) s.yaxis = this.axes.y; - else if (s.yaxis == 2) s.yaxis = this.axes.y2; - - // Apply missing options to the series. - for (var t in flotr.graphTypes){ - s[t] = _.extend(_.clone(this.options[t]), s[t]); - } - s.mouse = _.extend(_.clone(this.options.mouse), s.mouse); - - if (_.isUndefined(s.shadowSize)) s.shadowSize = this.options.shadowSize; - } - }, - - _setEl: function(el) { - if (!el) throw 'The target container doesn\'t exist'; - else if (el.graph instanceof Graph) el.graph.destroy(); - else if (!el.clientWidth) throw 'The target container must be visible'; - - el.graph = this; - this.el = el; - } -}; - -Flotr.Graph = Graph; - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/Series.js b/addons/web_graph/static/lib/flotr2/js/Series.js deleted file mode 100644 index e9a0c0fbeaa..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/Series.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Flotr Series Library - */ - -(function () { - -var - _ = Flotr._; - -function Series (o) { - _.extend(this, o); -} - -Series.prototype = { - - getRange: function () { - - var - data = this.data, - length = data.length, - xmin = Number.MAX_VALUE, - ymin = Number.MAX_VALUE, - xmax = -Number.MAX_VALUE, - ymax = -Number.MAX_VALUE, - xused = false, - yused = false, - x, y, i; - - if (length < 0 || this.hide) return false; - - for (i = 0; i < length; i++) { - x = data[i][0]; - y = data[i][1]; - if (x < xmin) { xmin = x; xused = true; } - if (x > xmax) { xmax = x; xused = true; } - if (y < ymin) { ymin = y; yused = true; } - if (y > ymax) { ymax = y; yused = true; } - } - - return { - xmin : xmin, - xmax : xmax, - ymin : ymin, - ymax : ymax, - xused : xused, - yused : yused - }; - } -}; - -_.extend(Series, { - /** - * Collects dataseries from input and parses the series into the right format. It returns an Array - * of Objects each having at least the 'data' key set. - * @param {Array, Object} data - Object or array of dataseries - * @return {Array} Array of Objects parsed into the right format ({(...,) data: [[x1,y1], [x2,y2], ...] (, ...)}) - */ - getSeries: function(data){ - return _.map(data, function(s){ - var series; - if (s.data) { - series = new Series(); - _.extend(series, s); - } else { - series = new Series({data:s}); - } - return series; - }); - } -}); - -Flotr.Series = Series; - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/Text.js b/addons/web_graph/static/lib/flotr2/js/Text.js deleted file mode 100644 index f24cf7ac4bf..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/Text.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Text Utilities - */ -(function () { - -var - F = Flotr, - D = F.DOM, - _ = F._, - -Text = function (o) { - this.o = o; -}; - -Text.prototype = { - - dimensions : function (text, canvasStyle, htmlStyle, className) { - - if (!text) return { width : 0, height : 0 }; - - return (this.o.html) ? - this.html(text, this.o.element, htmlStyle, className) : - this.canvas(text, canvasStyle); - }, - - canvas : function (text, style) { - - if (!this.o.textEnabled) return; - style = style || {}; - - var - metrics = this.measureText(text, style), - width = metrics.width, - height = style.size || F.defaultOptions.fontSize, - angle = style.angle || 0, - cosAngle = Math.cos(angle), - sinAngle = Math.sin(angle), - widthPadding = 2, - heightPadding = 6, - bounds; - - bounds = { - width: Math.abs(cosAngle * width) + Math.abs(sinAngle * height) + widthPadding, - height: Math.abs(sinAngle * width) + Math.abs(cosAngle * height) + heightPadding - }; - - return bounds; - }, - - html : function (text, element, style, className) { - - var div = D.create('div'); - - D.setStyles(div, { 'position' : 'absolute', 'top' : '-10000px' }); - D.insert(div, '
    ' + text + '
    '); - D.insert(this.o.element, div); - - return D.size(div); - }, - - measureText : function (text, style) { - - var - context = this.o.ctx, - metrics; - - if (!context.fillText || (F.isIphone && context.measure)) { - return { width : context.measure(text, style)}; - } - - style = _.extend({ - size: F.defaultOptions.fontSize, - weight: 1, - angle: 0 - }, style); - - context.save(); - context.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif"; - metrics = context.measureText(text); - context.restore(); - - return metrics; - } -}; - -Flotr.Text = Text; - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/crosshair.js b/addons/web_graph/static/lib/flotr2/js/plugins/crosshair.js deleted file mode 100644 index 611ebf85800..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/crosshair.js +++ /dev/null @@ -1,84 +0,0 @@ -(function () { - -var D = Flotr.DOM; - -Flotr.addPlugin('crosshair', { - options: { - mode: null, // => one of null, 'x', 'y' or 'xy' - color: '#FF0000', // => crosshair color - hideCursor: true // => hide the cursor when the crosshair is shown - }, - callbacks: { - 'flotr:mousemove': function(e, pos) { - if (this.options.crosshair.mode) { - this.crosshair.clearCrosshair(); - this.crosshair.drawCrosshair(pos); - } - } - }, - /** - * Draws the selection box. - */ - drawCrosshair: function(pos) { - var octx = this.octx, - options = this.options.crosshair, - plotOffset = this.plotOffset, - x = plotOffset.left + pos.relX + 0.5, - y = plotOffset.top + pos.relY + 0.5; - - if (pos.relX < 0 || pos.relY < 0 || pos.relX > this.plotWidth || pos.relY > this.plotHeight) { - this.el.style.cursor = null; - D.removeClass(this.el, 'flotr-crosshair'); - return; - } - - if (options.hideCursor) { - this.el.style.cursor = 'none'; - D.addClass(this.el, 'flotr-crosshair'); - } - - octx.save(); - octx.strokeStyle = options.color; - octx.lineWidth = 1; - octx.beginPath(); - - if (options.mode.indexOf('x') != -1) { - octx.moveTo(x, plotOffset.top); - octx.lineTo(x, plotOffset.top + this.plotHeight); - } - - if (options.mode.indexOf('y') != -1) { - octx.moveTo(plotOffset.left, y); - octx.lineTo(plotOffset.left + this.plotWidth, y); - } - - octx.stroke(); - octx.restore(); - }, - /** - * Removes the selection box from the overlay canvas. - */ - clearCrosshair: function() { - - var - plotOffset = this.plotOffset, - position = this.lastMousePos, - context = this.octx; - - if (position) { - context.clearRect( - position.relX + plotOffset.left, - plotOffset.top, - 1, - this.plotHeight + 1 - ); - context.clearRect( - plotOffset.left, - position.relY + plotOffset.top, - this.plotWidth + 1, - 1 - ); - } - } -}); -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/download.js b/addons/web_graph/static/lib/flotr2/js/plugins/download.js deleted file mode 100644 index 5d585325be9..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/download.js +++ /dev/null @@ -1,51 +0,0 @@ -(function() { - -var - D = Flotr.DOM, - _ = Flotr._; - -function getImage (type, canvas, width, height) { - - // TODO add scaling for w / h - var - mime = 'image/'+type, - data = canvas.toDataURL(mime), - image = new Image(); - image.src = data; - return image; -} - -Flotr.addPlugin('download', { - - saveImage: function (type, width, height, replaceCanvas) { - var image = null; - if (Flotr.isIE && Flotr.isIE < 9) { - image = ''+this.canvas.firstChild.innerHTML+''; - return window.open().document.write(image); - } - - if (type !== 'jpeg' && type !== 'png') return; - - image = getImage(type, this.canvas, width, height); - - if (_.isElement(image) && replaceCanvas) { - this.download.restoreCanvas(); - D.hide(this.canvas); - D.hide(this.overlay); - D.setStyles({position: 'absolute'}); - D.insert(this.el, image); - this.saveImageElement = image; - } else { - return window.open(image.src); - } - }, - - restoreCanvas: function() { - D.show(this.canvas); - D.show(this.overlay); - if (this.saveImageElement) this.el.removeChild(this.saveImageElement); - this.saveImageElement = null; - } -}); - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/grid.js b/addons/web_graph/static/lib/flotr2/js/plugins/grid.js deleted file mode 100644 index ab90d8d591a..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/grid.js +++ /dev/null @@ -1,208 +0,0 @@ -(function () { - -var E = Flotr.EventAdapter, - _ = Flotr._; - -Flotr.addPlugin('graphGrid', { - - callbacks: { - 'flotr:beforedraw' : function () { - this.graphGrid.drawGrid(); - }, - 'flotr:afterdraw' : function () { - this.graphGrid.drawOutline(); - } - }, - - drawGrid: function(){ - - var - ctx = this.ctx, - options = this.options, - grid = options.grid, - verticalLines = grid.verticalLines, - horizontalLines = grid.horizontalLines, - minorVerticalLines = grid.minorVerticalLines, - minorHorizontalLines = grid.minorHorizontalLines, - plotHeight = this.plotHeight, - plotWidth = this.plotWidth, - a, v, i, j; - - if(verticalLines || minorVerticalLines || - horizontalLines || minorHorizontalLines){ - E.fire(this.el, 'flotr:beforegrid', [this.axes.x, this.axes.y, options, this]); - } - ctx.save(); - ctx.lineWidth = 1; - ctx.strokeStyle = grid.tickColor; - - function circularHorizontalTicks (ticks) { - for(i = 0; i < ticks.length; ++i){ - var ratio = ticks[i].v / a.max; - for(j = 0; j <= sides; ++j){ - ctx[j === 0 ? 'moveTo' : 'lineTo']( - Math.cos(j*coeff+angle)*radius*ratio, - Math.sin(j*coeff+angle)*radius*ratio - ); - } - } - } - function drawGridLines (ticks, callback) { - _.each(_.pluck(ticks, 'v'), function(v){ - // Don't show lines on upper and lower bounds. - if ((v <= a.min || v >= a.max) || - (v == a.min || v == a.max) && grid.outlineWidth) - return; - callback(Math.floor(a.d2p(v)) + ctx.lineWidth/2); - }); - } - function drawVerticalLines (x) { - ctx.moveTo(x, 0); - ctx.lineTo(x, plotHeight); - } - function drawHorizontalLines (y) { - ctx.moveTo(0, y); - ctx.lineTo(plotWidth, y); - } - - if (grid.circular) { - ctx.translate(this.plotOffset.left+plotWidth/2, this.plotOffset.top+plotHeight/2); - var radius = Math.min(plotHeight, plotWidth)*options.radar.radiusRatio/2, - sides = this.axes.x.ticks.length, - coeff = 2*(Math.PI/sides), - angle = -Math.PI/2; - - // Draw grid lines in vertical direction. - ctx.beginPath(); - - a = this.axes.y; - - if(horizontalLines){ - circularHorizontalTicks(a.ticks); - } - if(minorHorizontalLines){ - circularHorizontalTicks(a.minorTicks); - } - - if(verticalLines){ - _.times(sides, function(i){ - ctx.moveTo(0, 0); - ctx.lineTo(Math.cos(i*coeff+angle)*radius, Math.sin(i*coeff+angle)*radius); - }); - } - ctx.stroke(); - } - else { - ctx.translate(this.plotOffset.left, this.plotOffset.top); - - // Draw grid background, if present in options. - if(grid.backgroundColor){ - ctx.fillStyle = this.processColor(grid.backgroundColor, {x1: 0, y1: 0, x2: plotWidth, y2: plotHeight}); - ctx.fillRect(0, 0, plotWidth, plotHeight); - } - - ctx.beginPath(); - - a = this.axes.x; - if (verticalLines) drawGridLines(a.ticks, drawVerticalLines); - if (minorVerticalLines) drawGridLines(a.minorTicks, drawVerticalLines); - - a = this.axes.y; - if (horizontalLines) drawGridLines(a.ticks, drawHorizontalLines); - if (minorHorizontalLines) drawGridLines(a.minorTicks, drawHorizontalLines); - - ctx.stroke(); - } - - ctx.restore(); - if(verticalLines || minorVerticalLines || - horizontalLines || minorHorizontalLines){ - E.fire(this.el, 'flotr:aftergrid', [this.axes.x, this.axes.y, options, this]); - } - }, - - drawOutline: function(){ - var - that = this, - options = that.options, - grid = options.grid, - outline = grid.outline, - ctx = that.ctx, - backgroundImage = grid.backgroundImage, - plotOffset = that.plotOffset, - leftOffset = plotOffset.left, - topOffset = plotOffset.top, - plotWidth = that.plotWidth, - plotHeight = that.plotHeight, - v, img, src, left, top, globalAlpha; - - if (!grid.outlineWidth) return; - - ctx.save(); - - if (grid.circular) { - ctx.translate(leftOffset + plotWidth / 2, topOffset + plotHeight / 2); - var radius = Math.min(plotHeight, plotWidth) * options.radar.radiusRatio / 2, - sides = this.axes.x.ticks.length, - coeff = 2*(Math.PI/sides), - angle = -Math.PI/2; - - // Draw axis/grid border. - ctx.beginPath(); - ctx.lineWidth = grid.outlineWidth; - ctx.strokeStyle = grid.color; - ctx.lineJoin = 'round'; - - for(i = 0; i <= sides; ++i){ - ctx[i === 0 ? 'moveTo' : 'lineTo'](Math.cos(i*coeff+angle)*radius, Math.sin(i*coeff+angle)*radius); - } - //ctx.arc(0, 0, radius, 0, Math.PI*2, true); - - ctx.stroke(); - } - else { - ctx.translate(leftOffset, topOffset); - - // Draw axis/grid border. - var lw = grid.outlineWidth, - orig = 0.5-lw+((lw+1)%2/2), - lineTo = 'lineTo', - moveTo = 'moveTo'; - ctx.lineWidth = lw; - ctx.strokeStyle = grid.color; - ctx.lineJoin = 'miter'; - ctx.beginPath(); - ctx.moveTo(orig, orig); - plotWidth = plotWidth - (lw / 2) % 1; - plotHeight = plotHeight + lw / 2; - ctx[outline.indexOf('n') !== -1 ? lineTo : moveTo](plotWidth, orig); - ctx[outline.indexOf('e') !== -1 ? lineTo : moveTo](plotWidth, plotHeight); - ctx[outline.indexOf('s') !== -1 ? lineTo : moveTo](orig, plotHeight); - ctx[outline.indexOf('w') !== -1 ? lineTo : moveTo](orig, orig); - ctx.stroke(); - ctx.closePath(); - } - - ctx.restore(); - - if (backgroundImage) { - - src = backgroundImage.src || backgroundImage; - left = (parseInt(backgroundImage.left, 10) || 0) + plotOffset.left; - top = (parseInt(backgroundImage.top, 10) || 0) + plotOffset.top; - img = new Image(); - - img.onload = function() { - ctx.save(); - if (backgroundImage.alpha) ctx.globalAlpha = backgroundImage.alpha; - ctx.globalCompositeOperation = 'destination-over'; - ctx.drawImage(img, 0, 0, img.width, img.height, left, top, plotWidth, plotHeight); - ctx.restore(); - }; - - img.src = src; - } - } -}); - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/handles.js b/addons/web_graph/static/lib/flotr2/js/plugins/handles.js deleted file mode 100644 index 92fd3247fdf..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/handles.js +++ /dev/null @@ -1,199 +0,0 @@ -/** - * Selection Handles Plugin - * - * Depends upon options.selection.mode - * - * Options - * show - True enables the handles plugin. - * drag - Left and Right drag handles - * scroll - Scrolling handle - */ -(function () { - -var D = Flotr.DOM; - -Flotr.addPlugin('handles', { - - options: { - show: false, - drag: true, - scroll: true - }, - - callbacks: { - 'flotr:afterinit': init, - 'flotr:select': handleSelect, - 'flotr:mousedown': reset, - 'flotr:mousemove': mouseMoveHandler - } - -}); - - -function init() { - - var - options = this.options, - handles = this.handles, - el = this.el, - scroll, left, right, container; - - if (!options.selection.mode || !options.handles.show || 'ontouchstart' in el) return; - - handles.initialized = true; - - container = D.node('
    '); - options = options.handles; - - // Drag handles - if (options.drag) { - right = D.node('
    '); - left = D.node('
    '); - D.insert(container, right); - D.insert(container, left); - D.hide(left); - D.hide(right); - handles.left = left; - handles.right = right; - - this.observe(left, 'mousedown', function () { - handles.moveHandler = leftMoveHandler; - }); - this.observe(right, 'mousedown', function () { - handles.moveHandler = rightMoveHandler; - }); - } - - // Scroll handle - if (options.scroll) { - scroll = D.node('
    '); - D.insert(container, scroll); - D.hide(scroll); - handles.scroll = scroll; - this.observe(scroll, 'mousedown', function () { - handles.moveHandler = scrollMoveHandler; - }); - } - - this.observe(document, 'mouseup', function() { - handles.moveHandler = null; - }); - - D.insert(el, container); -} - - -function handleSelect(selection) { - - if (!this.handles.initialized) return; - - var - handles = this.handles, - options = this.options.handles, - left = handles.left, - right = handles.right, - scroll = handles.scroll; - - if (options) { - if (options.drag) { - positionDrag(this, left, selection.x1); - positionDrag(this, right, selection.x2); - } - - if (options.scroll) { - positionScroll( - this, - scroll, - selection.x1, - selection.x2 - ); - } - } -} - -function positionDrag(graph, handle, x) { - - D.show(handle); - - var size = D.size(handle), - l = Math.round(graph.axes.x.d2p(x) - size.width / 2), - t = (graph.plotHeight - size.height) / 2; - - D.setStyles(handle, { - 'left' : l+'px', - 'top' : t+'px' - }); -} - -function positionScroll(graph, handle, x1, x2) { - - D.show(handle); - - var size = D.size(handle), - l = Math.round(graph.axes.x.d2p(x1)), - t = (graph.plotHeight) - size.height / 2, - w = (graph.axes.x.d2p(x2) - graph.axes.x.d2p(x1)); - - D.setStyles(handle, { - 'left' : l+'px', - 'top' : t+'px', - 'width': w+'px' - }); -} - -function reset() { - - if (!this.handles.initialized) return; - - var - handles = this.handles; - if (handles) { - D.hide(handles.left); - D.hide(handles.right); - D.hide(handles.scroll); - } -} - -function mouseMoveHandler(e, position) { - - if (!this.handles.initialized) return; - if (!this.handles.moveHandler) return; - - var - delta = position.dX, - selection = this.selection.selection, - area = this.selection.getArea(), - handles = this.handles; - - handles.moveHandler(area, delta); - checkSwap(area, handles); - - this.selection.setSelection(area); -} - -function checkSwap (area, handles) { - var moveHandler = handles.moveHandler; - if (area.x1 > area.x2) { - if (moveHandler == leftMoveHandler) { - moveHandler = rightMoveHandler; - } else if (moveHandler == rightMoveHandler) { - moveHandler = leftMoveHandler; - } - handles.moveHandler = moveHandler; - } -} - -function leftMoveHandler(area, delta) { - area.x1 += delta; -} - -function rightMoveHandler(area, delta) { - area.x2 += delta; -} - -function scrollMoveHandler(area, delta) { - area.x1 += delta; - area.x2 += delta; -} - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/hit.js b/addons/web_graph/static/lib/flotr2/js/plugins/hit.js deleted file mode 100644 index eeff570df35..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/hit.js +++ /dev/null @@ -1,337 +0,0 @@ -(function () { - -var - D = Flotr.DOM, - _ = Flotr._, - flotr = Flotr, - S_MOUSETRACK = '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;'; - -Flotr.addPlugin('hit', { - callbacks: { - 'flotr:mousemove': function(e, pos) { - this.hit.track(pos); - }, - 'flotr:click': function(pos) { - this.hit.track(pos); - }, - 'flotr:mouseout': function() { - this.hit.clearHit(); - } - }, - track : function (pos) { - if (this.options.mouse.track || _.any(this.series, function(s){return s.mouse && s.mouse.track;})) { - this.hit.hit(pos); - } - }, - /** - * Try a method on a graph type. If the method exists, execute it. - * @param {Object} series - * @param {String} method Method name. - * @param {Array} args Arguments applied to method. - * @return executed successfully or failed. - */ - executeOnType: function(s, method, args){ - var - success = false, - options; - - if (!_.isArray(s)) s = [s]; - - function e(s, index) { - _.each(_.keys(flotr.graphTypes), function (type) { - if (s[type] && s[type].show && this[type][method]) { - options = this.getOptions(s, type); - - options.fill = !!s.mouse.fillColor; - options.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity}); - options.color = s.mouse.lineColor; - options.context = this.octx; - options.index = index; - - if (args) options.args = args; - this[type][method].call(this[type], options); - success = true; - } - }, this); - } - _.each(s, e, this); - - return success; - }, - /** - * Updates the mouse tracking point on the overlay. - */ - drawHit: function(n){ - var octx = this.octx, - s = n.series; - - if (s.mouse.lineColor) { - octx.save(); - octx.lineWidth = (s.points ? s.points.lineWidth : 1); - octx.strokeStyle = s.mouse.lineColor; - octx.fillStyle = this.processColor(s.mouse.fillColor || '#ffffff', {opacity: s.mouse.fillOpacity}); - octx.translate(this.plotOffset.left, this.plotOffset.top); - - if (!this.hit.executeOnType(s, 'drawHit', n)) { - var xa = n.xaxis, - ya = n.yaxis; - - octx.beginPath(); - // TODO fix this (points) should move to general testable graph mixin - octx.arc(xa.d2p(n.x), ya.d2p(n.y), s.points.radius || s.mouse.radius, 0, 2 * Math.PI, true); - octx.fill(); - octx.stroke(); - octx.closePath(); - } - octx.restore(); - } - this.prevHit = n; - }, - /** - * Removes the mouse tracking point from the overlay. - */ - clearHit: function(){ - var prev = this.prevHit, - octx = this.octx, - plotOffset = this.plotOffset; - octx.save(); - octx.translate(plotOffset.left, plotOffset.top); - if (prev) { - if (!this.hit.executeOnType(prev.series, 'clearHit', this.prevHit)) { - // TODO fix this (points) should move to general testable graph mixin - var - s = prev.series, - lw = (s.points ? s.points.lineWidth : 1); - offset = (s.points.radius || s.mouse.radius) + lw; - octx.clearRect( - prev.xaxis.d2p(prev.x) - offset, - prev.yaxis.d2p(prev.y) - offset, - offset*2, - offset*2 - ); - } - D.hide(this.mouseTrack); - this.prevHit = null; - } - octx.restore(); - }, - /** - * Retrieves the nearest data point from the mouse cursor. If it's within - * a certain range, draw a point on the overlay canvas and display the x and y - * value of the data. - * @param {Object} mouse - Object that holds the relative x and y coordinates of the cursor. - */ - hit: function(mouse){ - - var - options = this.options, - prevHit = this.prevHit, - closest, sensibility, dataIndex, seriesIndex, series, value, xaxis, yaxis; - - if (this.series.length === 0) return; - - // Nearest data element. - // dist, x, y, relX, relY, absX, absY, sAngle, eAngle, fraction, mouse, - // xaxis, yaxis, series, index, seriesIndex - n = { - relX : mouse.relX, - relY : mouse.relY, - absX : mouse.absX, - absY : mouse.absY - }; - - if (options.mouse.trackY && - !options.mouse.trackAll && - this.hit.executeOnType(this.series, 'hit', [mouse, n])) - { - - if (!_.isUndefined(n.seriesIndex)) { - series = this.series[n.seriesIndex]; - n.series = series; - n.mouse = series.mouse; - n.xaxis = series.xaxis; - n.yaxis = series.yaxis; - } - } else { - - closest = this.hit.closest(mouse); - - if (closest) { - - closest = options.mouse.trackY ? closest.point : closest.x; - seriesIndex = closest.seriesIndex; - series = this.series[seriesIndex]; - xaxis = series.xaxis; - yaxis = series.yaxis; - sensibility = 2 * series.mouse.sensibility; - - if - (options.mouse.trackAll || - (closest.distanceX < sensibility / xaxis.scale && - (!options.mouse.trackY || closest.distanceY < sensibility / yaxis.scale))) - { - n.series = series; - n.xaxis = series.xaxis; - n.yaxis = series.yaxis; - n.mouse = series.mouse; - n.x = closest.x; - n.y = closest.y; - n.dist = closest.distance; - n.index = closest.dataIndex; - n.seriesIndex = seriesIndex; - } - } - } - - if (!prevHit || (prevHit.index !== n.index || prevHit.seriesIndex !== n.seriesIndex)) { - this.hit.clearHit(); - if (n.series && n.mouse && n.mouse.track) { - this.hit.drawMouseTrack(n); - this.hit.drawHit(n); - Flotr.EventAdapter.fire(this.el, 'flotr:hit', [n, this]); - } - } - }, - - closest : function (mouse) { - - var - series = this.series, - options = this.options, - mouseX = mouse.x, - mouseY = mouse.y, - compare = Number.MAX_VALUE, - compareX = Number.MAX_VALUE, - closest = {}, - closestX = {}, - check = false, - serie, data, - distance, distanceX, distanceY, - x, y, i, j; - - function setClosest (o) { - o.distance = distance; - o.distanceX = distanceX; - o.distanceY = distanceY; - o.seriesIndex = i; - o.dataIndex = j; - o.x = x; - o.y = y; - } - - for (i = 0; i < series.length; i++) { - - serie = series[i]; - data = serie.data; - - if (data.length) check = true; - - for (j = data.length; j--;) { - - x = data[j][0]; - y = data[j][1]; - - if (x === null || y === null) continue; - - // don't check if the point isn't visible in the current range - if (x < serie.xaxis.min || x > serie.xaxis.max) continue; - - distanceX = Math.abs(x - mouseX); - distanceY = Math.abs(y - mouseY); - - // Skip square root for speed - distance = distanceX * distanceX + distanceY * distanceY; - - if (distance < compare) { - compare = distance; - setClosest(closest); - } - - if (distanceX < compareX) { - compareX = distanceX; - setClosest(closestX); - } - } - } - - return check ? { - point : closest, - x : closestX - } : false; - }, - - drawMouseTrack : function (n) { - - var - pos = '', - s = n.series, - p = n.mouse.position, - m = n.mouse.margin, - elStyle = S_MOUSETRACK, - mouseTrack = this.mouseTrack, - plotOffset = this.plotOffset, - left = plotOffset.left, - right = plotOffset.right, - bottom = plotOffset.bottom, - top = plotOffset.top, - decimals = n.mouse.trackDecimals, - options = this.options; - - // Create - if (!mouseTrack) { - mouseTrack = D.node('
    '); - this.mouseTrack = mouseTrack; - D.insert(this.el, mouseTrack); - } - - if (!n.mouse.relative) { // absolute to the canvas - - if (p.charAt(0) == 'n') pos += 'top:' + (m + top) + 'px;bottom:auto;'; - else if (p.charAt(0) == 's') pos += 'bottom:' + (m + bottom) + 'px;top:auto;'; - if (p.charAt(1) == 'e') pos += 'right:' + (m + right) + 'px;left:auto;'; - else if (p.charAt(1) == 'w') pos += 'left:' + (m + left) + 'px;right:auto;'; - - // Bars - } else if (s.bars.show) { - pos += 'bottom:' + (m - top - n.yaxis.d2p(n.y/2) + this.canvasHeight) + 'px;top:auto;'; - pos += 'left:' + (m + left + n.xaxis.d2p(n.x - options.bars.barWidth/2)) + 'px;right:auto;'; - - // Pie - } else if (s.pie.show) { - var center = { - x: (this.plotWidth)/2, - y: (this.plotHeight)/2 - }, - radius = (Math.min(this.canvasWidth, this.canvasHeight) * s.pie.sizeRatio) / 2, - bisection = n.sAngle (isX ? graph.plotWidth : graph.plotHeight)) { continue; } - - Flotr.drawText( - ctx, tick.label, - leftOffset(graph, isX, isFirst, offset), - topOffset(graph, isX, isFirst, offset), - style - ); - - // Only draw on axis y2 - if (!isX && !isFirst) { - ctx.save(); - ctx.strokeStyle = style.color; - ctx.beginPath(); - ctx.moveTo(graph.plotOffset.left + graph.plotWidth - 8, graph.plotOffset.top + axis.d2p(tick.v)); - ctx.lineTo(graph.plotOffset.left + graph.plotWidth, graph.plotOffset.top + axis.d2p(tick.v)); - ctx.stroke(); - ctx.restore(); - } - } - - function continueShowingLabels (axis) { - return axis.options.showLabels && axis.used; - } - function leftOffset (graph, isX, isFirst, offset) { - return graph.plotOffset.left + - (isX ? offset : - (isFirst ? - -options.grid.labelMargin : - options.grid.labelMargin + graph.plotWidth)); - } - function topOffset (graph, isX, isFirst, offset) { - return graph.plotOffset.top + - (isX ? options.grid.labelMargin : offset) + - ((isX && isFirst) ? graph.plotHeight : 0); - } - } - - function drawLabelHtml (graph, axis) { - var - isX = axis.orientation === 1, - isFirst = axis.n === 1, - name = '', - left, style, top, - offset = graph.plotOffset; - - if (!isX && !isFirst) { - ctx.save(); - ctx.strokeStyle = axis.options.color || options.grid.color; - ctx.beginPath(); - } - - if (axis.options.showLabels && (isFirst ? true : axis.used)) { - for (i = 0; i < axis.ticks.length; ++i) { - tick = axis.ticks[i]; - if (!tick.label || !tick.label.length || - ((isX ? offset.left : offset.top) + axis.d2p(tick.v) < 0) || - ((isX ? offset.left : offset.top) + axis.d2p(tick.v) > (isX ? graph.canvasWidth : graph.canvasHeight))) { - continue; - } - top = offset.top + - (isX ? - ((isFirst ? 1 : -1 ) * (graph.plotHeight + options.grid.labelMargin)) : - axis.d2p(tick.v) - axis.maxLabel.height / 2); - left = isX ? (offset.left + axis.d2p(tick.v) - xBoxWidth / 2) : 0; - - name = ''; - if (i === 0) { - name = ' first'; - } else if (i === axis.ticks.length - 1) { - name = ' last'; - } - name += isX ? ' flotr-grid-label-x' : ' flotr-grid-label-y'; - - html += [ - '
    ' + tick.label + '
    ' - ].join(' '); - - if (!isX && !isFirst) { - ctx.moveTo(offset.left + graph.plotWidth - 8, offset.top + axis.d2p(tick.v)); - ctx.lineTo(offset.left + graph.plotWidth, offset.top + axis.d2p(tick.v)); - } - } - } - } - } - -}); -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/legend.js b/addons/web_graph/static/lib/flotr2/js/plugins/legend.js deleted file mode 100644 index d130cb5e90b..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/legend.js +++ /dev/null @@ -1,179 +0,0 @@ -(function () { - -var - D = Flotr.DOM, - _ = Flotr._; - -Flotr.addPlugin('legend', { - options: { - show: true, // => setting to true will show the legend, hide otherwise - noColumns: 1, // => number of colums in legend table // @todo: doesn't work for HtmlText = false - labelFormatter: function(v){return v;}, // => fn: string -> string - labelBoxBorderColor: '#CCCCCC', // => border color for the little label boxes - labelBoxWidth: 14, - labelBoxHeight: 10, - labelBoxMargin: 5, - labelBoxOpacity: 0.4, - container: null, // => container (as jQuery object) to put legend in, null means default on top of graph - position: 'nw', // => position of default legend container within plot - margin: 5, // => distance from grid edge to default legend container within plot - backgroundColor: null, // => null means auto-detect - backgroundOpacity: 0.85// => set to 0 to avoid background, set to 1 for a solid background - }, - callbacks: { - 'flotr:afterinit': function() { - this.legend.insertLegend(); - } - }, - /** - * Adds a legend div to the canvas container or draws it on the canvas. - */ - insertLegend: function(){ - - if(!this.options.legend.show) - return; - - var series = this.series, - plotOffset = this.plotOffset, - options = this.options, - legend = options.legend, - fragments = [], - rowStarted = false, - ctx = this.ctx, - itemCount = _.filter(series, function(s) {return (s.label && !s.hide);}).length, - p = legend.position, - m = legend.margin, - i, label, color; - - if (itemCount) { - if (!options.HtmlText && this.textEnabled && !legend.container) { - var style = { - size: options.fontSize*1.1, - color: options.grid.color - }; - - var lbw = legend.labelBoxWidth, - lbh = legend.labelBoxHeight, - lbm = legend.labelBoxMargin, - offsetX = plotOffset.left + m, - offsetY = plotOffset.top + m; - - // We calculate the labels' max width - var labelMaxWidth = 0; - for(i = series.length - 1; i > -1; --i){ - if(!series[i].label || series[i].hide) continue; - label = legend.labelFormatter(series[i].label); - labelMaxWidth = Math.max(labelMaxWidth, this._text.measureText(label, style).width); - } - - var legendWidth = Math.round(lbw + lbm*3 + labelMaxWidth), - legendHeight = Math.round(itemCount*(lbm+lbh) + lbm); - - if(p.charAt(0) == 's') offsetY = plotOffset.top + this.plotHeight - (m + legendHeight); - if(p.charAt(1) == 'e') offsetX = plotOffset.left + this.plotWidth - (m + legendWidth); - - // Legend box - color = this.processColor(legend.backgroundColor || 'rgb(240,240,240)', {opacity: legend.backgroundOpacity || 0.1}); - - ctx.fillStyle = color; - ctx.fillRect(offsetX, offsetY, legendWidth, legendHeight); - ctx.strokeStyle = legend.labelBoxBorderColor; - ctx.strokeRect(Flotr.toPixel(offsetX), Flotr.toPixel(offsetY), legendWidth, legendHeight); - - // Legend labels - var x = offsetX + lbm; - var y = offsetY + lbm; - for(i = 0; i < series.length; i++){ - if(!series[i].label || series[i].hide) continue; - label = legend.labelFormatter(series[i].label); - - ctx.fillStyle = series[i].color; - ctx.fillRect(x, y, lbw-1, lbh-1); - - ctx.strokeStyle = legend.labelBoxBorderColor; - ctx.lineWidth = 1; - ctx.strokeRect(Math.ceil(x)-1.5, Math.ceil(y)-1.5, lbw+2, lbh+2); - - // Legend text - Flotr.drawText(ctx, label, x + lbw + lbm, y + lbh, style); - - y += lbh + lbm; - } - } - else { - for(i = 0; i < series.length; ++i){ - if(!series[i].label || series[i].hide) continue; - - if(i % legend.noColumns === 0){ - fragments.push(rowStarted ? '
    ' : ''); - rowStarted = true; - } - - // @TODO remove requirement on bars - var s = series[i], - boxWidth = legend.labelBoxWidth, - boxHeight = legend.labelBoxHeight, - opacityValue = (s.bars ? s.bars.fillOpacity : legend.labelBoxOpacity), - opacity = 'opacity:' + opacityValue + ';filter:alpha(opacity=' + opacityValue*100 + ');'; - - label = legend.labelFormatter(s.label); - color = 'background-color:' + ((s.bars && s.bars.show && s.bars.fillColor && s.bars.fill) ? s.bars.fillColor : s.color) + ';'; - - fragments.push( - '', - '' - ); - } - if(rowStarted) fragments.push(''); - - if(fragments.length > 0){ - var table = '
     '+(a.label||String.fromCharCode(65+b))+"
    ', - '
    ', - '
    ', // Border - '
    ', // Background - '
    ', - '
    ', - '
    ', label, '
    ' + fragments.join('') + '
    '; - if(legend.container){ - D.insert(legend.container, table); - } - else { - var styles = {position: 'absolute', 'z-index': 2}; - - if(p.charAt(0) == 'n') { styles.top = (m + plotOffset.top) + 'px'; styles.bottom = 'auto'; } - else if(p.charAt(0) == 's') { styles.bottom = (m + plotOffset.bottom) + 'px'; styles.top = 'auto'; } - if(p.charAt(1) == 'e') { styles.right = (m + plotOffset.right) + 'px'; styles.left = 'auto'; } - else if(p.charAt(1) == 'w') { styles.left = (m + plotOffset.left) + 'px'; styles.right = 'auto'; } - - var div = D.create('div'), size; - div.className = 'flotr-legend'; - D.setStyles(div, styles); - D.insert(div, table); - D.insert(this.el, div); - - if(!legend.backgroundOpacity) - return; - - var c = legend.backgroundColor || options.grid.backgroundColor || '#ffffff'; - - _.extend(styles, D.size(div), { - 'backgroundColor': c, - 'z-index': 1 - }); - styles.width += 'px'; - styles.height += 'px'; - - // Put in the transparent background separately to avoid blended labels and - div = D.create('div'); - div.className = 'flotr-legend-bg'; - D.setStyles(div, styles); - D.opacity(div, legend.backgroundOpacity); - D.insert(div, ' '); - D.insert(this.el, div); - } - } - } - } - } -}); -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/selection.js b/addons/web_graph/static/lib/flotr2/js/plugins/selection.js deleted file mode 100644 index bb508840d6d..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/selection.js +++ /dev/null @@ -1,278 +0,0 @@ -/** - * Selection Handles Plugin - * - * - * Options - * show - True enables the handles plugin. - * drag - Left and Right drag handles - * scroll - Scrolling handle - */ -(function () { - -function isLeftClick (e, type) { - return (e.which ? (e.which === 1) : (e.button === 0 || e.button === 1)); -} - -function boundX(x, graph) { - return Math.min(Math.max(0, x), graph.plotWidth - 1); -} - -function boundY(y, graph) { - return Math.min(Math.max(0, y), graph.plotHeight); -} - -var - D = Flotr.DOM, - E = Flotr.EventAdapter, - _ = Flotr._; - - -Flotr.addPlugin('selection', { - - options: { - pinchOnly: null, // Only select on pinch - mode: null, // => one of null, 'x', 'y' or 'xy' - color: '#B6D9FF', // => selection box color - fps: 20 // => frames-per-second - }, - - callbacks: { - 'flotr:mouseup' : function (event) { - - var - options = this.options.selection, - selection = this.selection, - pointer = this.getEventPosition(event); - - if (!options || !options.mode) return; - if (selection.interval) clearInterval(selection.interval); - - if (this.multitouches) { - selection.updateSelection(); - } else - if (!options.pinchOnly) { - selection.setSelectionPos(selection.selection.second, pointer); - } - selection.clearSelection(); - - if(selection.selecting && selection.selectionIsSane()){ - selection.drawSelection(); - selection.fireSelectEvent(); - this.ignoreClick = true; - } - }, - 'flotr:mousedown' : function (event) { - - var - options = this.options.selection, - selection = this.selection, - pointer = this.getEventPosition(event); - - if (!options || !options.mode) return; - if (!options.mode || (!isLeftClick(event) && _.isUndefined(event.touches))) return; - if (!options.pinchOnly) selection.setSelectionPos(selection.selection.first, pointer); - if (selection.interval) clearInterval(selection.interval); - - this.lastMousePos.pageX = null; - selection.selecting = false; - selection.interval = setInterval( - _.bind(selection.updateSelection, this), - 1000 / options.fps - ); - }, - 'flotr:destroy' : function (event) { - clearInterval(this.selection.interval); - } - }, - - // TODO This isn't used. Maybe it belongs in the draw area and fire select event methods? - getArea: function() { - - var s = this.selection.selection, - first = s.first, - second = s.second; - - return { - x1: Math.min(first.x, second.x), - x2: Math.max(first.x, second.x), - y1: Math.min(first.y, second.y), - y2: Math.max(first.y, second.y) - }; - }, - - selection: {first: {x: -1, y: -1}, second: {x: -1, y: -1}}, - prevSelection: null, - interval: null, - - /** - * Fires the 'flotr:select' event when the user made a selection. - */ - fireSelectEvent: function(name){ - var a = this.axes, - s = this.selection.selection, - x1, x2, y1, y2; - - name = name || 'select'; - - x1 = a.x.p2d(s.first.x); - x2 = a.x.p2d(s.second.x); - y1 = a.y.p2d(s.first.y); - y2 = a.y.p2d(s.second.y); - - E.fire(this.el, 'flotr:'+name, [{ - x1:Math.min(x1, x2), - y1:Math.min(y1, y2), - x2:Math.max(x1, x2), - y2:Math.max(y1, y2), - xfirst:x1, xsecond:x2, yfirst:y1, ysecond:y2 - }, this]); - }, - - /** - * Allows the user the manually select an area. - * @param {Object} area - Object with coordinates to select. - */ - setSelection: function(area, preventEvent){ - var options = this.options, - xa = this.axes.x, - ya = this.axes.y, - vertScale = ya.scale, - hozScale = xa.scale, - selX = options.selection.mode.indexOf('x') != -1, - selY = options.selection.mode.indexOf('y') != -1, - s = this.selection.selection; - - this.selection.clearSelection(); - - s.first.y = boundY((selX && !selY) ? 0 : (ya.max - area.y1) * vertScale, this); - s.second.y = boundY((selX && !selY) ? this.plotHeight - 1: (ya.max - area.y2) * vertScale, this); - s.first.x = boundX((selY && !selX) ? 0 : area.x1, this); - s.second.x = boundX((selY && !selX) ? this.plotWidth : area.x2, this); - - this.selection.drawSelection(); - if (!preventEvent) - this.selection.fireSelectEvent(); - }, - - /** - * Calculates the position of the selection. - * @param {Object} pos - Position object. - * @param {Event} event - Event object. - */ - setSelectionPos: function(pos, pointer) { - var mode = this.options.selection.mode, - selection = this.selection.selection; - - if(mode.indexOf('x') == -1) { - pos.x = (pos == selection.first) ? 0 : this.plotWidth; - }else{ - pos.x = boundX(pointer.relX, this); - } - - if (mode.indexOf('y') == -1) { - pos.y = (pos == selection.first) ? 0 : this.plotHeight - 1; - }else{ - pos.y = boundY(pointer.relY, this); - } - }, - /** - * Draws the selection box. - */ - drawSelection: function() { - - this.selection.fireSelectEvent('selecting'); - - var s = this.selection.selection, - octx = this.octx, - options = this.options, - plotOffset = this.plotOffset, - prevSelection = this.selection.prevSelection; - - if (prevSelection && - s.first.x == prevSelection.first.x && - s.first.y == prevSelection.first.y && - s.second.x == prevSelection.second.x && - s.second.y == prevSelection.second.y) { - return; - } - - octx.save(); - octx.strokeStyle = this.processColor(options.selection.color, {opacity: 0.8}); - octx.lineWidth = 1; - octx.lineJoin = 'miter'; - octx.fillStyle = this.processColor(options.selection.color, {opacity: 0.4}); - - this.selection.prevSelection = { - first: { x: s.first.x, y: s.first.y }, - second: { x: s.second.x, y: s.second.y } - }; - - var x = Math.min(s.first.x, s.second.x), - y = Math.min(s.first.y, s.second.y), - w = Math.abs(s.second.x - s.first.x), - h = Math.abs(s.second.y - s.first.y); - - octx.fillRect(x + plotOffset.left+0.5, y + plotOffset.top+0.5, w, h); - octx.strokeRect(x + plotOffset.left+0.5, y + plotOffset.top+0.5, w, h); - octx.restore(); - }, - - /** - * Updates (draws) the selection box. - */ - updateSelection: function(){ - if (!this.lastMousePos.pageX) return; - - this.selection.selecting = true; - - if (this.multitouches) { - this.selection.setSelectionPos(this.selection.selection.first, this.getEventPosition(this.multitouches[0])); - this.selection.setSelectionPos(this.selection.selection.second, this.getEventPosition(this.multitouches[1])); - } else - if (this.options.selection.pinchOnly) { - return; - } else { - this.selection.setSelectionPos(this.selection.selection.second, this.lastMousePos); - } - - this.selection.clearSelection(); - - if(this.selection.selectionIsSane()) { - this.selection.drawSelection(); - } - }, - - /** - * Removes the selection box from the overlay canvas. - */ - clearSelection: function() { - if (!this.selection.prevSelection) return; - - var prevSelection = this.selection.prevSelection, - lw = 1, - plotOffset = this.plotOffset, - x = Math.min(prevSelection.first.x, prevSelection.second.x), - y = Math.min(prevSelection.first.y, prevSelection.second.y), - w = Math.abs(prevSelection.second.x - prevSelection.first.x), - h = Math.abs(prevSelection.second.y - prevSelection.first.y); - - this.octx.clearRect(x + plotOffset.left - lw + 0.5, - y + plotOffset.top - lw, - w + 2 * lw + 0.5, - h + 2 * lw + 0.5); - - this.selection.prevSelection = null; - }, - /** - * Determines whether or not the selection is sane and should be drawn. - * @return {Boolean} - True when sane, false otherwise. - */ - selectionIsSane: function(){ - var s = this.selection.selection; - return Math.abs(s.second.x - s.first.x) >= 5 || - Math.abs(s.second.y - s.first.y) >= 5; - } - -}); - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/spreadsheet.js b/addons/web_graph/static/lib/flotr2/js/plugins/spreadsheet.js deleted file mode 100644 index d75cb1991b1..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/spreadsheet.js +++ /dev/null @@ -1,296 +0,0 @@ -/** Spreadsheet **/ -(function() { - -function getRowLabel(value){ - if (this.options.spreadsheet.tickFormatter){ - //TODO maybe pass the xaxis formatter to the custom tick formatter as an opt-out? - return this.options.spreadsheet.tickFormatter(value); - } - else { - var t = _.find(this.axes.x.ticks, function(t){return t.v == value;}); - if (t) { - return t.label; - } - return value; - } -} - -var - D = Flotr.DOM, - _ = Flotr._; - -Flotr.addPlugin('spreadsheet', { - options: { - show: false, // => show the data grid using two tabs - tabGraphLabel: 'Graph', - tabDataLabel: 'Data', - toolbarDownload: 'Download CSV', // @todo: add better language support - toolbarSelectAll: 'Select all', - csvFileSeparator: ',', - decimalSeparator: '.', - tickFormatter: null, - initialTab: 'graph' - }, - /** - * Builds the tabs in the DOM - */ - callbacks: { - 'flotr:afterconstruct': function(){ - // @TODO necessary? - //this.el.select('.flotr-tabs-group,.flotr-datagrid-container').invoke('remove'); - - if (!this.options.spreadsheet.show) return; - - var ss = this.spreadsheet, - container = D.node('
    '), - graph = D.node('
    '+this.options.spreadsheet.tabGraphLabel+'
    '), - data = D.node('
    '+this.options.spreadsheet.tabDataLabel+'
    '), - offset; - - ss.tabsContainer = container; - ss.tabs = { graph : graph, data : data }; - - D.insert(container, graph); - D.insert(container, data); - D.insert(this.el, container); - - offset = D.size(data).height + 2; - this.plotOffset.bottom += offset; - - D.setStyles(container, {top: this.canvasHeight-offset+'px'}); - - this. - observe(graph, 'click', function(){ss.showTab('graph');}). - observe(data, 'click', function(){ss.showTab('data');}); - if (this.options.spreadsheet.initialTab !== 'graph'){ - ss.showTab(this.options.spreadsheet.initialTab); - } - } - }, - /** - * Builds a matrix of the data to make the correspondance between the x values and the y values : - * X value => Y values from the axes - * @return {Array} The data grid - */ - loadDataGrid: function(){ - if (this.seriesData) return this.seriesData; - - var s = this.series, - rows = {}; - - /* The data grid is a 2 dimensions array. There is a row for each X value. - * Each row contains the x value and the corresponding y value for each serie ('undefined' if there isn't one) - **/ - _.each(s, function(serie, i){ - _.each(serie.data, function (v) { - var x = v[0], - y = v[1], - r = rows[x]; - if (r) { - r[i+1] = y; - } else { - var newRow = []; - newRow[0] = x; - newRow[i+1] = y; - rows[x] = newRow; - } - }); - }); - - // The data grid is sorted by x value - this.seriesData = _.sortBy(rows, function(row, x){ - return parseInt(x, 10); - }); - return this.seriesData; - }, - /** - * Constructs the data table for the spreadsheet - * @todo make a spreadsheet manager (Flotr.Spreadsheet) - * @return {Element} The resulting table element - */ - constructDataGrid: function(){ - // If the data grid has already been built, nothing to do here - if (this.spreadsheet.datagrid) return this.spreadsheet.datagrid; - - var s = this.series, - datagrid = this.spreadsheet.loadDataGrid(), - colgroup = [''], - buttonDownload, buttonSelect, t; - - // First row : series' labels - var html = ['']; - html.push(''); - _.each(s, function(serie,i){ - html.push(''); - colgroup.push(''); - }); - html.push(''); - // Data rows - _.each(datagrid, function(row){ - html.push(''); - _.times(s.length+1, function(i){ - var tag = 'td', - value = row[i], - // TODO: do we really want to handle problems with floating point - // precision here? - content = (!_.isUndefined(value) ? Math.round(value*100000)/100000 : ''); - if (i === 0) { - tag = 'th'; - var label = getRowLabel.call(this, content); - if (label) content = label; - } - - html.push('<'+tag+(tag=='th'?' scope="row"':'')+'>'+content+''); - }, this); - html.push(''); - }, this); - colgroup.push(''); - t = D.node(html.join('')); - - /** - * @TODO disabled this - if (!Flotr.isIE || Flotr.isIE == 9) { - function handleMouseout(){ - t.select('colgroup col.hover, th.hover').invoke('removeClassName', 'hover'); - } - function handleMouseover(e){ - var td = e.element(), - siblings = td.previousSiblings(); - t.select('th[scope=col]')[siblings.length-1].addClassName('hover'); - t.select('colgroup col')[siblings.length].addClassName('hover'); - } - _.each(t.select('td'), function(td) { - Flotr.EventAdapter. - observe(td, 'mouseover', handleMouseover). - observe(td, 'mouseout', handleMouseout); - }); - } - */ - - buttonDownload = D.node( - ''); - - buttonSelect = D.node( - ''); - - this. - observe(buttonDownload, 'click', _.bind(this.spreadsheet.downloadCSV, this)). - observe(buttonSelect, 'click', _.bind(this.spreadsheet.selectAllData, this)); - - var toolbar = D.node('
    '); - D.insert(toolbar, buttonDownload); - D.insert(toolbar, buttonSelect); - - var containerHeight =this.canvasHeight - D.size(this.spreadsheet.tabsContainer).height-2, - container = D.node('
    '); - - D.insert(container, toolbar); - D.insert(container, t); - D.insert(this.el, container); - this.spreadsheet.datagrid = t; - this.spreadsheet.container = container; - - return t; - }, - /** - * Shows the specified tab, by its name - * @todo make a tab manager (Flotr.Tabs) - * @param {String} tabName - The tab name - */ - showTab: function(tabName){ - if (this.spreadsheet.activeTab === tabName){ - return; - } - switch(tabName) { - case 'graph': - D.hide(this.spreadsheet.container); - D.removeClass(this.spreadsheet.tabs.data, 'selected'); - D.addClass(this.spreadsheet.tabs.graph, 'selected'); - break; - case 'data': - if (!this.spreadsheet.datagrid) - this.spreadsheet.constructDataGrid(); - D.show(this.spreadsheet.container); - D.addClass(this.spreadsheet.tabs.data, 'selected'); - D.removeClass(this.spreadsheet.tabs.graph, 'selected'); - break; - default: - throw 'Illegal tab name: ' + tabName; - } - this.spreadsheet.activeTab = tabName; - }, - /** - * Selects the data table in the DOM for copy/paste - */ - selectAllData: function(){ - if (this.spreadsheet.tabs) { - var selection, range, doc, win, node = this.spreadsheet.constructDataGrid(); - - this.spreadsheet.showTab('data'); - - // deferred to be able to select the table - setTimeout(function () { - if ((doc = node.ownerDocument) && (win = doc.defaultView) && - win.getSelection && doc.createRange && - (selection = window.getSelection()) && - selection.removeAllRanges) { - range = doc.createRange(); - range.selectNode(node); - selection.removeAllRanges(); - selection.addRange(range); - } - else if (document.body && document.body.createTextRange && - (range = document.body.createTextRange())) { - range.moveToElementText(node); - range.select(); - } - }, 0); - return true; - } - else return false; - }, - /** - * Converts the data into CSV in order to download a file - */ - downloadCSV: function(){ - var csv = '', - series = this.series, - options = this.options, - dg = this.spreadsheet.loadDataGrid(), - separator = encodeURIComponent(options.spreadsheet.csvFileSeparator); - - if (options.spreadsheet.decimalSeparator === options.spreadsheet.csvFileSeparator) { - throw "The decimal separator is the same as the column separator ("+options.spreadsheet.decimalSeparator+")"; - } - - // The first row - _.each(series, function(serie, i){ - csv += separator+'"'+(serie.label || String.fromCharCode(65+i)).replace(/\"/g, '\\"')+'"'; - }); - - csv += "%0D%0A"; // \r\n - - // For each row - csv += _.reduce(dg, function(memo, row){ - var rowLabel = getRowLabel.call(this, row[0]) || ''; - rowLabel = '"'+(rowLabel+'').replace(/\"/g, '\\"')+'"'; - var numbers = row.slice(1).join(separator); - if (options.spreadsheet.decimalSeparator !== '.') { - numbers = numbers.replace(/\./g, options.spreadsheet.decimalSeparator); - } - return memo + rowLabel+separator+numbers+"%0D%0A"; // \t and \r\n - }, '', this); - - if (Flotr.isIE && Flotr.isIE < 9) { - csv = csv.replace(new RegExp(separator, 'g'), decodeURIComponent(separator)).replace(/%0A/g, '\n').replace(/%0D/g, '\r'); - window.open().document.write(csv); - } - else window.open('data:text/csv,'+csv); - } -}); -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/plugins/titles.js b/addons/web_graph/static/lib/flotr2/js/plugins/titles.js deleted file mode 100644 index cf95d9e7c80..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/plugins/titles.js +++ /dev/null @@ -1,177 +0,0 @@ -(function () { - -var D = Flotr.DOM; - -Flotr.addPlugin('titles', { - callbacks: { - 'flotr:afterdraw': function() { - this.titles.drawTitles(); - } - }, - /** - * Draws the title and the subtitle - */ - drawTitles : function () { - var html, - options = this.options, - margin = options.grid.labelMargin, - ctx = this.ctx, - a = this.axes; - - if (!options.HtmlText && this.textEnabled) { - var style = { - size: options.fontSize, - color: options.grid.color, - textAlign: 'center' - }; - - // Add subtitle - if (options.subtitle){ - Flotr.drawText( - ctx, options.subtitle, - this.plotOffset.left + this.plotWidth/2, - this.titleHeight + this.subtitleHeight - 2, - style - ); - } - - style.weight = 1.5; - style.size *= 1.5; - - // Add title - if (options.title){ - Flotr.drawText( - ctx, options.title, - this.plotOffset.left + this.plotWidth/2, - this.titleHeight - 2, - style - ); - } - - style.weight = 1.8; - style.size *= 0.8; - - // Add x axis title - if (a.x.options.title && a.x.used){ - style.textAlign = a.x.options.titleAlign || 'center'; - style.textBaseline = 'top'; - style.angle = Flotr.toRad(a.x.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.x.options.title, - this.plotOffset.left + this.plotWidth/2, - this.plotOffset.top + a.x.maxLabel.height + this.plotHeight + 2 * margin, - style - ); - } - - // Add x2 axis title - if (a.x2.options.title && a.x2.used){ - style.textAlign = a.x2.options.titleAlign || 'center'; - style.textBaseline = 'bottom'; - style.angle = Flotr.toRad(a.x2.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.x2.options.title, - this.plotOffset.left + this.plotWidth/2, - this.plotOffset.top - a.x2.maxLabel.height - 2 * margin, - style - ); - } - - // Add y axis title - if (a.y.options.title && a.y.used){ - style.textAlign = a.y.options.titleAlign || 'right'; - style.textBaseline = 'middle'; - style.angle = Flotr.toRad(a.y.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.y.options.title, - this.plotOffset.left - a.y.maxLabel.width - 2 * margin, - this.plotOffset.top + this.plotHeight / 2, - style - ); - } - - // Add y2 axis title - if (a.y2.options.title && a.y2.used){ - style.textAlign = a.y2.options.titleAlign || 'left'; - style.textBaseline = 'middle'; - style.angle = Flotr.toRad(a.y2.options.titleAngle); - style = Flotr.getBestTextAlign(style.angle, style); - Flotr.drawText( - ctx, a.y2.options.title, - this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin, - this.plotOffset.top + this.plotHeight / 2, - style - ); - } - } - else { - html = []; - - // Add title - if (options.title) - html.push( - '
    ', options.title, '
    ' - ); - - // Add subtitle - if (options.subtitle) - html.push( - '
    ', options.subtitle, '
    ' - ); - - html.push(''); - - html.push('
    '); - - // Add x axis title - if (a.x.options.title && a.x.used) - html.push( - '
    ', a.x.options.title, '
    ' - ); - - // Add x2 axis title - if (a.x2.options.title && a.x2.used) - html.push( - '
    ', a.x2.options.title, '
    ' - ); - - // Add y axis title - if (a.y.options.title && a.y.used) - html.push( - '
    ', a.y.options.title, '
    ' - ); - - // Add y2 axis title - if (a.y2.options.title && a.y2.used) - html.push( - '
    ', a.y2.options.title, '
    ' - ); - - html = html.join(''); - - var div = D.create('div'); - D.setStyles({ - color: options.grid.color - }); - div.className = 'flotr-titles'; - D.insert(this.el, div); - D.insert(div, html); - } - } -}); -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/types/bars.js b/addons/web_graph/static/lib/flotr2/js/types/bars.js deleted file mode 100644 index 03e7988b785..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/bars.js +++ /dev/null @@ -1,274 +0,0 @@ -/** Bars **/ -Flotr.addType('bars', { - - options: { - show: false, // => setting to true will show bars, false will hide - lineWidth: 2, // => in pixels - barWidth: 1, // => in units of the x axis - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillColor: null, // => fill color - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - horizontal: false, // => horizontal bars (x and y inverted) - stacked: false, // => stacked bar charts - centered: true, // => center the bars to their x axis value - topPadding: 0.1 // => top padding in percent - }, - - stack : { - positive : [], - negative : [], - _positive : [], // Shadow - _negative : [] // Shadow - }, - - draw : function (options) { - var - context = options.context; - - context.save(); - context.lineJoin = 'miter'; - // @TODO linewidth not interpreted the right way. - context.lineWidth = options.lineWidth; - context.strokeStyle = options.color; - if (options.fill) context.fillStyle = options.fillStyle; - - this.plot(options); - - context.restore(); - }, - - plot : function (options) { - - var - data = options.data, - context = options.context, - shadowSize = options.shadowSize, - i, geometry, left, top, width, height; - - if (data.length < 1) return; - - this.translate(context, options.horizontal); - - for (i = 0; i < data.length; i++) { - - geometry = this.getBarGeometry(data[i][0], data[i][1], options); - if (geometry === null) continue; - - left = geometry.left; - top = geometry.top; - width = geometry.width; - height = geometry.height; - - if (options.fill) context.fillRect(left, top, width, height); - if (shadowSize) { - context.save(); - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.fillRect(left + shadowSize, top + shadowSize, width, height); - context.restore(); - } - if (options.lineWidth) { - context.strokeRect(left, top, width, height); - } - } - }, - - translate : function (context, horizontal) { - if (horizontal) { - context.rotate(-Math.PI / 2); - context.scale(-1, 1); - } - }, - - getBarGeometry : function (x, y, options) { - - var - horizontal = options.horizontal, - barWidth = options.barWidth, - centered = options.centered, - stack = options.stacked ? this.stack : false, - lineWidth = options.lineWidth, - bisection = centered ? barWidth / 2 : 0, - xScale = horizontal ? options.yScale : options.xScale, - yScale = horizontal ? options.xScale : options.yScale, - xValue = horizontal ? y : x, - yValue = horizontal ? x : y, - stackOffset = 0, - stackValue, left, right, top, bottom; - - // Stacked bars - if (stack) { - stackValue = yValue > 0 ? stack.positive : stack.negative; - stackOffset = stackValue[xValue] || stackOffset; - stackValue[xValue] = stackOffset + yValue; - } - - left = xScale(xValue - bisection); - right = xScale(xValue + barWidth - bisection); - top = yScale(yValue + stackOffset); - bottom = yScale(stackOffset); - - // TODO for test passing... probably looks better without this - if (bottom < 0) bottom = 0; - - // TODO Skipping... - // if (right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) continue; - - return (x === null || y === null) ? null : { - x : xValue, - y : yValue, - xScale : xScale, - yScale : yScale, - top : top, - left : Math.min(left, right) - lineWidth / 2, - width : Math.abs(right - left) - lineWidth, - height : bottom - top - }; - }, - - hit : function (options) { - var - data = options.data, - args = options.args, - mouse = args[0], - n = args[1], - x = mouse.x, - y = mouse.y, - hitGeometry = this.getBarGeometry(x, y, options), - width = hitGeometry.width / 2, - left = hitGeometry.left, - geometry, i; - - for (i = data.length; i--;) { - geometry = this.getBarGeometry(data[i][0], data[i][1], options); - if (geometry.y > hitGeometry.y && Math.abs(left - geometry.left) < width) { - n.x = data[i][0]; - n.y = data[i][1]; - n.index = i; - n.seriesIndex = options.index; - } - } - }, - - drawHit : function (options) { - // TODO hits for stacked bars; implement using calculateStack option? - var - context = options.context, - args = options.args, - geometry = this.getBarGeometry(args.x, args.y, options), - left = geometry.left, - top = geometry.top, - width = geometry.width, - height = geometry.height; - - context.save(); - context.strokeStyle = options.color; - context.lineWidth = options.lineWidth; - this.translate(context, options.horizontal); - - // Draw highlight - context.beginPath(); - context.moveTo(left, top + height); - context.lineTo(left, top); - context.lineTo(left + width, top); - context.lineTo(left + width, top + height); - if (options.fill) { - context.fillStyle = options.fillStyle; - context.fill(); - } - context.stroke(); - context.closePath(); - - context.restore(); - }, - - clearHit: function (options) { - var - context = options.context, - args = options.args, - geometry = this.getBarGeometry(args.x, args.y, options), - left = geometry.left, - width = geometry.width, - top = geometry.top, - height = geometry.height, - lineWidth = 2 * options.lineWidth; - - context.save(); - this.translate(context, options.horizontal); - context.clearRect( - left - lineWidth, - Math.min(top, top + height) - lineWidth, - width + 2 * lineWidth, - Math.abs(height) + 2 * lineWidth - ); - context.restore(); - }, - - extendXRange : function (axis, data, options, bars) { - this._extendRange(axis, data, options, bars); - }, - - extendYRange : function (axis, data, options, bars) { - this._extendRange(axis, data, options, bars); - }, - _extendRange: function (axis, data, options, bars) { - - var - max = axis.options.max; - - if (_.isNumber(max) || _.isString(max)) return; - - var - newmin = axis.min, - newmax = axis.max, - horizontal = options.horizontal, - orientation = axis.orientation, - positiveSums = this.positiveSums || {}, - negativeSums = this.negativeSums || {}, - value, datum, index, j; - - // Sides of bars - if ((orientation == 1 && !horizontal) || (orientation == -1 && horizontal)) { - if (options.centered) { - newmax = Math.max(axis.datamax + options.barWidth, newmax); - newmin = Math.min(axis.datamin - options.barWidth, newmin); - } - } - - if (options.stacked && - ((orientation == 1 && horizontal) || (orientation == -1 && !horizontal))){ - - for (j = data.length; j--;) { - value = data[j][(orientation == 1 ? 1 : 0)]+''; - datum = data[j][(orientation == 1 ? 0 : 1)]; - - // Positive - if (datum > 0) { - positiveSums[value] = (positiveSums[value] || 0) + datum; - newmax = Math.max(newmax, positiveSums[value]); - } - - // Negative - else { - negativeSums[value] = (negativeSums[value] || 0) + datum; - newmin = Math.min(newmin, negativeSums[value]); - } - } - } - - // End of bars - if ((orientation == 1 && horizontal) || (orientation == -1 && !horizontal)) { - if (options.topPadding && (axis.max === axis.datamax || (options.stacked && this.stackMax !== newmax))) { - newmax += options.topPadding * (newmax - newmin); - } - } - - this.stackMin = newmin; - this.stackMax = newmax; - this.negativeSums = negativeSums; - this.positiveSums = positiveSums; - - axis.max = newmax; - axis.min = newmin; - } - -}); diff --git a/addons/web_graph/static/lib/flotr2/js/types/bubbles.js b/addons/web_graph/static/lib/flotr2/js/types/bubbles.js deleted file mode 100644 index a97c5a28a93..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/bubbles.js +++ /dev/null @@ -1,119 +0,0 @@ -/** Bubbles **/ -Flotr.addType('bubbles', { - options: { - show: false, // => setting to true will show radar chart, false will hide - lineWidth: 2, // => line width in pixels - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - baseRadius: 2 // => ratio of the radar, against the plot size - }, - draw : function (options) { - var - context = options.context, - shadowSize = options.shadowSize; - - context.save(); - context.lineWidth = options.lineWidth; - - // Shadows - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.strokeStyle = 'rgba(0,0,0,0.05)'; - this.plot(options, shadowSize / 2); - context.strokeStyle = 'rgba(0,0,0,0.1)'; - this.plot(options, shadowSize / 4); - - // Chart - context.strokeStyle = options.color; - context.fillStyle = options.fillStyle; - this.plot(options); - - context.restore(); - }, - plot : function (options, offset) { - - var - data = options.data, - context = options.context, - geometry, - i, x, y, z; - - offset = offset || 0; - - for (i = 0; i < data.length; ++i){ - - geometry = this.getGeometry(data[i], options); - - context.beginPath(); - context.arc(geometry.x + offset, geometry.y + offset, geometry.z, 0, 2 * Math.PI, true); - context.stroke(); - if (options.fill) context.fill(); - context.closePath(); - } - }, - getGeometry : function (point, options) { - return { - x : options.xScale(point[0]), - y : options.yScale(point[1]), - z : point[2] * options.baseRadius - }; - }, - hit : function (options) { - var - data = options.data, - args = options.args, - mouse = args[0], - n = args[1], - x = mouse.x, - y = mouse.y, - geometry, - dx, dy; - - for (i = data.length; i--;) { - geometry = this.getGeometry(data[i], options); - - dx = geometry.x - options.xScale(x); - dy = geometry.y - options.yScale(y); - - if (Math.sqrt(dx * dx + dy * dy) < geometry.z) { - n.x = data[i][0]; - n.y = data[i][1]; - n.index = i; - n.seriesIndex = options.index; - } - } - }, - drawHit : function (options) { - - var - context = options.context, - geometry = this.getGeometry(options.data[options.args.index], options); - - context.save(); - context.lineWidth = options.lineWidth; - context.fillStyle = options.fillStyle; - context.strokeStyle = options.color; - context.beginPath(); - context.arc(geometry.x, geometry.y, geometry.z, 0, 2 * Math.PI, true); - context.fill(); - context.stroke(); - context.closePath(); - context.restore(); - }, - clearHit : function (options) { - - var - context = options.context, - geometry = this.getGeometry(options.data[options.args.index], options), - offset = geometry.z + options.lineWidth; - - context.save(); - context.clearRect( - geometry.x - offset, - geometry.y - offset, - 2 * offset, - 2 * offset - ); - context.restore(); - } - // TODO Add a hit calculation method (like pie) -}); diff --git a/addons/web_graph/static/lib/flotr2/js/types/candles.js b/addons/web_graph/static/lib/flotr2/js/types/candles.js deleted file mode 100644 index 0e484b366cc..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/candles.js +++ /dev/null @@ -1,127 +0,0 @@ -/** Candles **/ -Flotr.addType('candles', { - options: { - show: false, // => setting to true will show candle sticks, false will hide - lineWidth: 1, // => in pixels - wickLineWidth: 1, // => in pixels - candleWidth: 0.6, // => in units of the x axis - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - upFillColor: '#00A8F0',// => up sticks fill color - downFillColor: '#CB4B4B',// => down sticks fill color - fillOpacity: 0.5, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - // TODO Test this barcharts option. - barcharts: false // => draw as barcharts (not standard bars but financial barcharts) - }, - - draw : function (options) { - - var - context = options.context; - - context.save(); - context.lineJoin = 'miter'; - context.lineCap = 'butt'; - // @TODO linewidth not interpreted the right way. - context.lineWidth = options.wickLineWidth || options.lineWidth; - - this.plot(options); - - context.restore(); - }, - - plot : function (options) { - - var - data = options.data, - context = options.context, - xScale = options.xScale, - yScale = options.yScale, - width = options.candleWidth / 2, - shadowSize = options.shadowSize, - lineWidth = options.lineWidth, - wickLineWidth = options.wickLineWidth, - pixelOffset = (wickLineWidth % 2) / 2, - color, - datum, x, y, - open, high, low, close, - left, right, bottom, top, bottom2, top2, - i; - - if (data.length < 1) return; - - for (i = 0; i < data.length; i++) { - datum = data[i]; - x = datum[0]; - open = datum[1]; - high = datum[2]; - low = datum[3]; - close = datum[4]; - left = xScale(x - width); - right = xScale(x + width); - bottom = yScale(low); - top = yScale(high); - bottom2 = yScale(Math.min(open, close)); - top2 = yScale(Math.max(open, close)); - - /* - // TODO skipping - if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) - continue; - */ - - color = options[open > close ? 'downFillColor' : 'upFillColor']; - - // Fill the candle. - // TODO Test the barcharts option - if (options.fill && !options.barcharts) { - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.fillRect(left + shadowSize, top2 + shadowSize, right - left, bottom2 - top2); - context.save(); - context.globalAlpha = options.fillOpacity; - context.fillStyle = color; - context.fillRect(left, top2 + lineWidth, right - left, bottom2 - top2); - context.restore(); - } - - // Draw candle outline/border, high, low. - if (lineWidth || wickLineWidth) { - - x = Math.floor((left + right) / 2) + pixelOffset; - - context.strokeStyle = color; - context.beginPath(); - - // TODO Again with the bartcharts - if (options.barcharts) { - - context.moveTo(x, Math.floor(top + width)); - context.lineTo(x, Math.floor(bottom + width)); - - y = Math.floor(open + width) + 0.5; - context.moveTo(Math.floor(left) + pixelOffset, y); - context.lineTo(x, y); - - y = Math.floor(close + width) + 0.5; - context.moveTo(Math.floor(right) + pixelOffset, y); - context.lineTo(x, y); - } else { - context.strokeRect(left, top2 + lineWidth, right - left, bottom2 - top2); - - context.moveTo(x, Math.floor(top2 + lineWidth)); - context.lineTo(x, Math.floor(top + lineWidth)); - context.moveTo(x, Math.floor(bottom2 + lineWidth)); - context.lineTo(x, Math.floor(bottom + lineWidth)); - } - - context.closePath(); - context.stroke(); - } - } - }, - extendXRange: function (axis, data, options) { - if (axis.options.max === null) { - axis.max = Math.max(axis.datamax + 0.5, axis.max); - axis.min = Math.min(axis.datamin - 0.5, axis.min); - } - } -}); diff --git a/addons/web_graph/static/lib/flotr2/js/types/gantt.js b/addons/web_graph/static/lib/flotr2/js/types/gantt.js deleted file mode 100644 index 1498bcb51cf..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/gantt.js +++ /dev/null @@ -1,229 +0,0 @@ -/** Gantt - * Base on data in form [s,y,d] where: - * y - executor or simply y value - * s - task start value - * d - task duration - * **/ -Flotr.addType('gantt', { - options: { - show: false, // => setting to true will show gantt, false will hide - lineWidth: 2, // => in pixels - barWidth: 1, // => in units of the x axis - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillColor: null, // => fill color - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - centered: true // => center the bars to their x axis value - }, - /** - * Draws gantt series in the canvas element. - * @param {Object} series - Series with options.gantt.show = true. - */ - draw: function(series) { - var ctx = this.ctx, - bw = series.gantt.barWidth, - lw = Math.min(series.gantt.lineWidth, bw); - - ctx.save(); - ctx.translate(this.plotOffset.left, this.plotOffset.top); - ctx.lineJoin = 'miter'; - - /** - * @todo linewidth not interpreted the right way. - */ - ctx.lineWidth = lw; - ctx.strokeStyle = series.color; - - ctx.save(); - this.gantt.plotShadows(series, bw, 0, series.gantt.fill); - ctx.restore(); - - if(series.gantt.fill){ - var color = series.gantt.fillColor || series.color; - ctx.fillStyle = this.processColor(color, {opacity: series.gantt.fillOpacity}); - } - - this.gantt.plot(series, bw, 0, series.gantt.fill); - ctx.restore(); - }, - plot: function(series, barWidth, offset, fill){ - var data = series.data; - if(data.length < 1) return; - - var xa = series.xaxis, - ya = series.yaxis, - ctx = this.ctx, i; - - for(i = 0; i < data.length; i++){ - var y = data[i][0], - s = data[i][1], - d = data[i][2], - drawLeft = true, drawTop = true, drawRight = true; - - if (s === null || d === null) continue; - - var left = s, - right = s + d, - bottom = y - (series.gantt.centered ? barWidth/2 : 0), - top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0); - - if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) - continue; - - if(left < xa.min){ - left = xa.min; - drawLeft = false; - } - - if(right > xa.max){ - right = xa.max; - if (xa.lastSerie != series) - drawTop = false; - } - - if(bottom < ya.min) - bottom = ya.min; - - if(top > ya.max){ - top = ya.max; - if (ya.lastSerie != series) - drawTop = false; - } - - /** - * Fill the bar. - */ - if(fill){ - ctx.beginPath(); - ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset); - ctx.lineTo(xa.d2p(left), ya.d2p(top) + offset); - ctx.lineTo(xa.d2p(right), ya.d2p(top) + offset); - ctx.lineTo(xa.d2p(right), ya.d2p(bottom) + offset); - ctx.fill(); - ctx.closePath(); - } - - /** - * Draw bar outline/border. - */ - if(series.gantt.lineWidth && (drawLeft || drawRight || drawTop)){ - ctx.beginPath(); - ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset); - - ctx[drawLeft ?'lineTo':'moveTo'](xa.d2p(left), ya.d2p(top) + offset); - ctx[drawTop ?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(top) + offset); - ctx[drawRight?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(bottom) + offset); - - ctx.stroke(); - ctx.closePath(); - } - } - }, - plotShadows: function(series, barWidth, offset){ - var data = series.data; - if(data.length < 1) return; - - var i, y, s, d, - xa = series.xaxis, - ya = series.yaxis, - ctx = this.ctx, - sw = this.options.shadowSize; - - for(i = 0; i < data.length; i++){ - y = data[i][0]; - s = data[i][1]; - d = data[i][2]; - - if (s === null || d === null) continue; - - var left = s, - right = s + d, - bottom = y - (series.gantt.centered ? barWidth/2 : 0), - top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0); - - if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max) - continue; - - if(left < xa.min) left = xa.min; - if(right > xa.max) right = xa.max; - if(bottom < ya.min) bottom = ya.min; - if(top > ya.max) top = ya.max; - - var width = xa.d2p(right)-xa.d2p(left)-((xa.d2p(right)+sw <= this.plotWidth) ? 0 : sw); - var height = ya.d2p(bottom)-ya.d2p(top)-((ya.d2p(bottom)+sw <= this.plotHeight) ? 0 : sw ); - - ctx.fillStyle = 'rgba(0,0,0,0.05)'; - ctx.fillRect(Math.min(xa.d2p(left)+sw, this.plotWidth), Math.min(ya.d2p(top)+sw, this.plotHeight), width, height); - } - }, - extendXRange: function(axis) { - if(axis.options.max === null){ - var newmin = axis.min, - newmax = axis.max, - i, j, x, s, g, - stackedSumsPos = {}, - stackedSumsNeg = {}, - lastSerie = null; - - for(i = 0; i < this.series.length; ++i){ - s = this.series[i]; - g = s.gantt; - - if(g.show && s.xaxis == axis) { - for (j = 0; j < s.data.length; j++) { - if (g.show) { - y = s.data[j][0]+''; - stackedSumsPos[y] = Math.max((stackedSumsPos[y] || 0), s.data[j][1]+s.data[j][2]); - lastSerie = s; - } - } - for (j in stackedSumsPos) { - newmax = Math.max(stackedSumsPos[j], newmax); - } - } - } - axis.lastSerie = lastSerie; - axis.max = newmax; - axis.min = newmin; - } - }, - extendYRange: function(axis){ - if(axis.options.max === null){ - var newmax = Number.MIN_VALUE, - newmin = Number.MAX_VALUE, - i, j, s, g, - stackedSumsPos = {}, - stackedSumsNeg = {}, - lastSerie = null; - - for(i = 0; i < this.series.length; ++i){ - s = this.series[i]; - g = s.gantt; - - if (g.show && !s.hide && s.yaxis == axis) { - var datamax = Number.MIN_VALUE, datamin = Number.MAX_VALUE; - for(j=0; j < s.data.length; j++){ - datamax = Math.max(datamax,s.data[j][0]); - datamin = Math.min(datamin,s.data[j][0]); - } - - if (g.centered) { - newmax = Math.max(datamax + 0.5, newmax); - newmin = Math.min(datamin - 0.5, newmin); - } - else { - newmax = Math.max(datamax + 1, newmax); - newmin = Math.min(datamin, newmin); - } - // For normal horizontal bars - if (g.barWidth + datamax > newmax){ - newmax = axis.max + g.barWidth; - } - } - } - axis.lastSerie = lastSerie; - axis.max = newmax; - axis.min = newmin; - axis.tickSize = Flotr.getTickSize(axis.options.noTicks, newmin, newmax, axis.options.tickDecimals); - } - } -}); diff --git a/addons/web_graph/static/lib/flotr2/js/types/lines.js b/addons/web_graph/static/lib/flotr2/js/types/lines.js deleted file mode 100644 index d65971b2dfe..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/lines.js +++ /dev/null @@ -1,275 +0,0 @@ -/** Lines **/ -Flotr.addType('lines', { - options: { - show: false, // => setting to true will show lines, false will hide - lineWidth: 2, // => line width in pixels - fill: false, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillBorder: false, // => draw a border around the fill - fillColor: null, // => fill color - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - steps: false, // => draw steps - stacked: false // => setting to true will show stacked lines, false will show normal lines - }, - - stack : { - values : [] - }, - - /** - * Draws lines series in the canvas element. - * @param {Object} options - */ - draw : function (options) { - - var - context = options.context, - lineWidth = options.lineWidth, - shadowSize = options.shadowSize, - offset; - - context.save(); - context.lineJoin = 'round'; - - if (shadowSize) { - - context.lineWidth = shadowSize / 2; - offset = lineWidth / 2 + context.lineWidth / 2; - - // @TODO do this instead with a linear gradient - context.strokeStyle = "rgba(0,0,0,0.1)"; - this.plot(options, offset + shadowSize / 2, false); - - context.strokeStyle = "rgba(0,0,0,0.2)"; - this.plot(options, offset, false); - } - - context.lineWidth = lineWidth; - context.strokeStyle = options.color; - - this.plot(options, 0, true); - - context.restore(); - }, - - plot : function (options, shadowOffset, incStack) { - - var - context = options.context, - width = options.width, - height = options.height, - xScale = options.xScale, - yScale = options.yScale, - data = options.data, - stack = options.stacked ? this.stack : false, - length = data.length - 1, - prevx = null, - prevy = null, - zero = yScale(0), - x1, x2, y1, y2, stack1, stack2, i; - - if (length < 1) return; - - context.beginPath(); - - for (i = 0; i < length; ++i) { - - // To allow empty values - if (data[i][1] === null || data[i+1][1] === null) continue; - - // Zero is infinity for log scales - // TODO handle zero for logarithmic - // if (xa.options.scaling === 'logarithmic' && (data[i][0] <= 0 || data[i+1][0] <= 0)) continue; - // if (ya.options.scaling === 'logarithmic' && (data[i][1] <= 0 || data[i+1][1] <= 0)) continue; - - x1 = xScale(data[i][0]); - x2 = xScale(data[i+1][0]); - - if (stack) { - - stack1 = stack.values[data[i][0]] || 0; - stack2 = stack.values[data[i+1][0]] || stack.values[data[i][0]] || 0; - - y1 = yScale(data[i][1] + stack1); - y2 = yScale(data[i+1][1] + stack2); - - if(incStack){ - stack.values[data[i][0]] = data[i][1]+stack1; - - if(i == length-1) - stack.values[data[i+1][0]] = data[i+1][1]+stack2; - } - } - else{ - y1 = yScale(data[i][1]); - y2 = yScale(data[i+1][1]); - } - - if ( - (y1 > height && y2 > height) || - (y1 < 0 && y2 < 0) || - (x1 < 0 && x2 < 0) || - (x1 > width && x2 > width) - ) continue; - - if((prevx != x1) || (prevy != y1 + shadowOffset)) - context.moveTo(x1, y1 + shadowOffset); - - prevx = x2; - prevy = y2 + shadowOffset; - if (options.steps) { - context.lineTo(prevx + shadowOffset / 2, y1 + shadowOffset); - context.lineTo(prevx + shadowOffset / 2, prevy); - } else { - context.lineTo(prevx, prevy); - } - } - - if (!options.fill || options.fill && !options.fillBorder) context.stroke(); - - // TODO stacked lines - if(!shadowOffset && options.fill){ - x1 = xScale(data[0][0]); - context.fillStyle = options.fillStyle; - context.lineTo(x2, zero); - context.lineTo(x1, zero); - context.lineTo(x1, yScale(data[0][1])); - context.fill(); - if (options.fillBorder) { - context.stroke(); - } - } - - context.closePath(); - }, - - // Perform any pre-render precalculations (this should be run on data first) - // - Pie chart total for calculating measures - // - Stacks for lines and bars - // precalculate : function () { - // } - // - // - // Get any bounds after pre calculation (axis can fetch this if does not have explicit min/max) - // getBounds : function () { - // } - // getMin : function () { - // } - // getMax : function () { - // } - // - // - // Padding around rendered elements - // getPadding : function () { - // } - - extendYRange : function (axis, data, options, lines) { - - var o = axis.options; - - // If stacked and auto-min - if (options.stacked && ((!o.max && o.max !== 0) || (!o.min && o.min !== 0))) { - - var - newmax = axis.max, - newmin = axis.min, - positiveSums = lines.positiveSums || {}, - negativeSums = lines.negativeSums || {}, - x, j; - - for (j = 0; j < data.length; j++) { - - x = data[j][0] + ''; - - // Positive - if (data[j][1] > 0) { - positiveSums[x] = (positiveSums[x] || 0) + data[j][1]; - newmax = Math.max(newmax, positiveSums[x]); - } - - // Negative - else { - negativeSums[x] = (negativeSums[x] || 0) + data[j][1]; - newmin = Math.min(newmin, negativeSums[x]); - } - } - - lines.negativeSums = negativeSums; - lines.positiveSums = positiveSums; - - axis.max = newmax; - axis.min = newmin; - } - - if (options.steps) { - - this.hit = function (options) { - var - data = options.data, - args = options.args, - yScale = options.yScale, - mouse = args[0], - length = data.length, - n = args[1], - x = mouse.x, - relY = mouse.relY, - i; - - for (i = 0; i < length - 1; i++) { - if (x >= data[i][0] && x <= data[i+1][0]) { - if (Math.abs(yScale(data[i][1]) - relY) < 8) { - n.x = data[i][0]; - n.y = data[i][1]; - n.index = i; - n.seriesIndex = options.index; - } - break; - } - } - }; - - this.drawHit = function (options) { - var - context = options.context, - args = options.args, - data = options.data, - xScale = options.xScale, - index = args.index, - x = xScale(args.x), - y = options.yScale(args.y), - x2; - - if (data.length - 1 > index) { - x2 = options.xScale(data[index + 1][0]); - context.save(); - context.strokeStyle = options.color; - context.lineWidth = options.lineWidth; - context.beginPath(); - context.moveTo(x, y); - context.lineTo(x2, y); - context.stroke(); - context.closePath(); - context.restore(); - } - }; - - this.clearHit = function (options) { - var - context = options.context, - args = options.args, - data = options.data, - xScale = options.xScale, - width = options.lineWidth, - index = args.index, - x = xScale(args.x), - y = options.yScale(args.y), - x2; - - if (data.length - 1 > index) { - x2 = options.xScale(data[index + 1][0]); - context.clearRect(x - width, y - width, x2 - x + 2 * width, 2 * width); - } - }; - } - } - -}); diff --git a/addons/web_graph/static/lib/flotr2/js/types/markers.js b/addons/web_graph/static/lib/flotr2/js/types/markers.js deleted file mode 100644 index ee1104e3568..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/markers.js +++ /dev/null @@ -1,140 +0,0 @@ -/** Markers **/ -/** - * Formats the marker labels. - * @param {Object} obj - Marker value Object {x:..,y:..} - * @return {String} Formatted marker string - */ -(function () { - -Flotr.defaultMarkerFormatter = function(obj){ - return (Math.round(obj.y*100)/100)+''; -}; - -Flotr.addType('markers', { - options: { - show: false, // => setting to true will show markers, false will hide - lineWidth: 1, // => line width of the rectangle around the marker - color: '#000000', // => text color - fill: false, // => fill or not the marekers' rectangles - fillColor: "#FFFFFF", // => fill color - fillOpacity: 0.4, // => fill opacity - stroke: false, // => draw the rectangle around the markers - position: 'ct', // => the markers position (vertical align: b, m, t, horizontal align: l, c, r) - verticalMargin: 0, // => the margin between the point and the text. - labelFormatter: Flotr.defaultMarkerFormatter, - fontSize: Flotr.defaultOptions.fontSize, - stacked: false, // => true if markers should be stacked - stackingType: 'b', // => define staching behavior, (b- bars like, a - area like) (see Issue 125 for details) - horizontal: false // => true if markers should be horizontal (For now only in a case on horizontal stacked bars, stacks should be calculated horizontaly) - }, - - // TODO test stacked markers. - stack : { - positive : [], - negative : [], - values : [] - }, - - draw : function (options) { - - var - data = options.data, - context = options.context, - stack = options.stacked ? options.stack : false, - stackType = options.stackingType, - stackOffsetNeg, - stackOffsetPos, - stackOffset, - i, x, y, label; - - context.save(); - context.lineJoin = 'round'; - context.lineWidth = options.lineWidth; - context.strokeStyle = 'rgba(0,0,0,0.5)'; - context.fillStyle = options.fillStyle; - - function stackPos (a, b) { - stackOffsetPos = stack.negative[a] || 0; - stackOffsetNeg = stack.positive[a] || 0; - if (b > 0) { - stack.positive[a] = stackOffsetPos + b; - return stackOffsetPos + b; - } else { - stack.negative[a] = stackOffsetNeg + b; - return stackOffsetNeg + b; - } - } - - for (i = 0; i < data.length; ++i) { - - x = data[i][0]; - y = data[i][1]; - - if (stack) { - if (stackType == 'b') { - if (options.horizontal) y = stackPos(y, x); - else x = stackPos(x, y); - } else if (stackType == 'a') { - stackOffset = stack.values[x] || 0; - stack.values[x] = stackOffset + y; - y = stackOffset + y; - } - } - - label = options.labelFormatter({x: x, y: y, index: i, data : data}); - this.plot(options.xScale(x), options.yScale(y), label, options); - } - context.restore(); - }, - plot: function(x, y, label, options) { - var context = options.context; - if (isImage(label) && !label.complete) { - throw 'Marker image not loaded.'; - } else { - this._plot(x, y, label, options); - } - }, - - _plot: function(x, y, label, options) { - var context = options.context, - margin = 2, - left = x, - top = y, - dim; - - if (isImage(label)) - dim = {height : label.height, width: label.width}; - else - dim = options.text.canvas(label); - - dim.width = Math.floor(dim.width+margin*2); - dim.height = Math.floor(dim.height+margin*2); - - if (options.position.indexOf('c') != -1) left -= dim.width/2 + margin; - else if (options.position.indexOf('l') != -1) left -= dim.width; - - if (options.position.indexOf('m') != -1) top -= dim.height/2 + margin; - else if (options.position.indexOf('t') != -1) top -= dim.height + options.verticalMargin; - else top += options.verticalMargin; - - left = Math.floor(left)+0.5; - top = Math.floor(top)+0.5; - - if(options.fill) - context.fillRect(left, top, dim.width, dim.height); - - if(options.stroke) - context.strokeRect(left, top, dim.width, dim.height); - - if (isImage(label)) - context.drawImage(label, left+margin, top+margin); - else - Flotr.drawText(context, label, left+margin, top+margin, {textBaseline: 'top', textAlign: 'left', size: options.fontSize, color: options.color}); - } -}); - -function isImage (i) { - return typeof i === 'object' && i.constructor && (Image ? true : i.constructor === Image); -} - -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/types/pie.js b/addons/web_graph/static/lib/flotr2/js/types/pie.js deleted file mode 100644 index ec932be5e6d..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/pie.js +++ /dev/null @@ -1,210 +0,0 @@ -/** Pie **/ -/** - * Formats the pies labels. - * @param {Object} slice - Slice object - * @return {String} Formatted pie label string - */ -(function () { - -var - _ = Flotr._; - -Flotr.defaultPieLabelFormatter = function (total, value) { - return (100 * value / total).toFixed(2)+'%'; -}; - -Flotr.addType('pie', { - options: { - show: false, // => setting to true will show bars, false will hide - lineWidth: 1, // => in pixels - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillColor: null, // => fill color - fillOpacity: 0.6, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - explode: 6, // => the number of pixels the splices will be far from the center - sizeRatio: 0.6, // => the size ratio of the pie relative to the plot - startAngle: Math.PI/4, // => the first slice start angle - labelFormatter: Flotr.defaultPieLabelFormatter, - pie3D: false, // => whether to draw the pie in 3 dimenstions or not (ineffective) - pie3DviewAngle: (Math.PI/2 * 0.8), - pie3DspliceThickness: 20 - }, - - draw : function (options) { - - // TODO 3D charts what? - - var - data = options.data, - context = options.context, - canvas = context.canvas, - lineWidth = options.lineWidth, - shadowSize = options.shadowSize, - sizeRatio = options.sizeRatio, - height = options.height, - width = options.width, - explode = options.explode, - color = options.color, - fill = options.fill, - fillStyle = options.fillStyle, - radius = Math.min(canvas.width, canvas.height) * sizeRatio / 2, - value = data[0][1], - html = [], - vScale = 1,//Math.cos(series.pie.viewAngle); - measure = Math.PI * 2 * value / this.total, - startAngle = this.startAngle || (2 * Math.PI * options.startAngle), // TODO: this initial startAngle is already in radians (fixing will be test-unstable) - endAngle = startAngle + measure, - bisection = startAngle + measure / 2, - label = options.labelFormatter(this.total, value), - //plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale; - explodeCoeff = explode + radius + 4, - distX = Math.cos(bisection) * explodeCoeff, - distY = Math.sin(bisection) * explodeCoeff, - textAlign = distX < 0 ? 'right' : 'left', - textBaseline = distY > 0 ? 'top' : 'bottom', - style, - x, y, - distX, distY; - - context.save(); - context.translate(width / 2, height / 2); - context.scale(1, vScale); - - x = Math.cos(bisection) * explode; - y = Math.sin(bisection) * explode; - - // Shadows - if (shadowSize > 0) { - this.plotSlice(x + shadowSize, y + shadowSize, radius, startAngle, endAngle, context); - if (fill) { - context.fillStyle = 'rgba(0,0,0,0.1)'; - context.fill(); - } - } - - this.plotSlice(x, y, radius, startAngle, endAngle, context); - if (fill) { - context.fillStyle = fillStyle; - context.fill(); - } - context.lineWidth = lineWidth; - context.strokeStyle = color; - context.stroke(); - - style = { - size : options.fontSize * 1.2, - color : options.fontColor, - weight : 1.5 - }; - - if (label) { - if (options.htmlText || !options.textEnabled) { - divStyle = 'position:absolute;' + textBaseline + ':' + (height / 2 + (textBaseline === 'top' ? distY : -distY)) + 'px;'; - divStyle += textAlign + ':' + (width / 2 + (textAlign === 'right' ? -distX : distX)) + 'px;'; - html.push('
    ', label, '
    '); - } - else { - style.textAlign = textAlign; - style.textBaseline = textBaseline; - Flotr.drawText(context, label, distX, distY, style); - } - } - - if (options.htmlText || !options.textEnabled) { - var div = Flotr.DOM.node('
    '); - Flotr.DOM.insert(div, html.join('')); - Flotr.DOM.insert(options.element, div); - } - - context.restore(); - - // New start angle - this.startAngle = endAngle; - this.slices = this.slices || []; - this.slices.push({ - radius : Math.min(canvas.width, canvas.height) * sizeRatio / 2, - x : x, - y : y, - explode : explode, - start : startAngle, - end : endAngle - }); - }, - plotSlice : function (x, y, radius, startAngle, endAngle, context) { - context.beginPath(); - context.moveTo(x, y); - context.arc(x, y, radius, startAngle, endAngle, false); - context.lineTo(x, y); - context.closePath(); - }, - hit : function (options) { - - var - data = options.data[0], - args = options.args, - index = options.index, - mouse = args[0], - n = args[1], - slice = this.slices[index], - x = mouse.relX - options.width / 2, - y = mouse.relY - options.height / 2, - r = Math.sqrt(x * x + y * y), - theta = Math.atan(y / x), - circle = Math.PI * 2, - explode = slice.explode || options.explode, - start = slice.start % circle, - end = slice.end % circle; - - if (x < 0) { - theta += Math.PI; - } else if (x > 0 && y < 0) { - theta += circle; - } - - if (r < slice.radius + explode && r > explode) { - if ((start > end && (theta < end || theta > start)) || - (theta > start && theta < end)) { - - // TODO Decouple this from hit plugin (chart shouldn't know what n means) - n.x = data[0]; - n.y = data[1]; - n.sAngle = start; - n.eAngle = end; - n.index = 0; - n.seriesIndex = index; - n.fraction = data[1] / this.total; - } - } - }, - drawHit: function (options) { - var - context = options.context, - slice = this.slices[options.args.seriesIndex]; - - context.save(); - context.translate(options.width / 2, options.height / 2); - this.plotSlice(slice.x, slice.y, slice.radius, slice.start, slice.end, context); - context.stroke(); - context.restore(); - }, - clearHit : function (options) { - var - context = options.context, - slice = this.slices[options.args.seriesIndex], - padding = 2 * options.lineWidth, - radius = slice.radius + padding; - - context.save(); - context.translate(options.width / 2, options.height / 2); - context.clearRect( - slice.x - radius, - slice.y - radius, - 2 * radius + padding, - 2 * radius + padding - ); - context.restore(); - }, - extendYRange : function (axis, data) { - this.total = (this.total || 0) + data[0][1]; - } -}); -})(); diff --git a/addons/web_graph/static/lib/flotr2/js/types/points.js b/addons/web_graph/static/lib/flotr2/js/types/points.js deleted file mode 100644 index ebb360e6fae..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/points.js +++ /dev/null @@ -1,66 +0,0 @@ -/** Points **/ -Flotr.addType('points', { - options: { - show: false, // => setting to true will show points, false will hide - radius: 3, // => point radius (pixels) - lineWidth: 2, // => line width in pixels - fill: true, // => true to fill the points with a color, false for (transparent) no fill - fillColor: '#FFFFFF', // => fill color - fillOpacity: 0.4 // => opacity of color inside the points - }, - - draw : function (options) { - var - context = options.context, - lineWidth = options.lineWidth, - shadowSize = options.shadowSize; - - context.save(); - - if (shadowSize > 0) { - context.lineWidth = shadowSize / 2; - - context.strokeStyle = 'rgba(0,0,0,0.1)'; - this.plot(options, shadowSize / 2 + context.lineWidth / 2); - - context.strokeStyle = 'rgba(0,0,0,0.2)'; - this.plot(options, context.lineWidth / 2); - } - - context.lineWidth = options.lineWidth; - context.strokeStyle = options.color; - context.fillStyle = options.fillColor || options.color; - - this.plot(options); - context.restore(); - }, - - plot : function (options, offset) { - var - data = options.data, - context = options.context, - xScale = options.xScale, - yScale = options.yScale, - i, x, y; - - for (i = data.length - 1; i > -1; --i) { - y = data[i][1]; - if (y === null) continue; - - x = xScale(data[i][0]); - y = yScale(y); - - if (x < 0 || x > options.width || y < 0 || y > options.height) continue; - - context.beginPath(); - if (offset) { - context.arc(x, y + offset, options.radius, 0, Math.PI, false); - } else { - context.arc(x, y, options.radius, 0, 2 * Math.PI, true); - if (options.fill) context.fill(); - } - context.stroke(); - context.closePath(); - } - } -}); diff --git a/addons/web_graph/static/lib/flotr2/js/types/radar.js b/addons/web_graph/static/lib/flotr2/js/types/radar.js deleted file mode 100644 index d693ddc78ec..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/radar.js +++ /dev/null @@ -1,60 +0,0 @@ -/** Radar **/ -Flotr.addType('radar', { - options: { - show: false, // => setting to true will show radar chart, false will hide - lineWidth: 2, // => line width in pixels - fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill - fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill - radiusRatio: 0.90 // => ratio of the radar, against the plot size - }, - draw : function (options) { - var - context = options.context, - shadowSize = options.shadowSize; - - context.save(); - context.translate(options.width / 2, options.height / 2); - context.lineWidth = options.lineWidth; - - // Shadow - context.fillStyle = 'rgba(0,0,0,0.05)'; - context.strokeStyle = 'rgba(0,0,0,0.05)'; - this.plot(options, shadowSize / 2); - context.strokeStyle = 'rgba(0,0,0,0.1)'; - this.plot(options, shadowSize / 4); - - // Chart - context.strokeStyle = options.color; - context.fillStyle = options.fillStyle; - this.plot(options); - - context.restore(); - }, - plot : function (options, offset) { - var - data = options.data, - context = options.context, - radius = Math.min(options.height, options.width) * options.radiusRatio / 2, - step = 2 * Math.PI / data.length, - angle = -Math.PI / 2, - i, ratio; - - offset = offset || 0; - - context.beginPath(); - for (i = 0; i < data.length; ++i) { - ratio = data[i][1] / this.max; - - context[i === 0 ? 'moveTo' : 'lineTo']( - Math.cos(i * step + angle) * radius * ratio + offset, - Math.sin(i * step + angle) * radius * ratio + offset - ); - } - context.closePath(); - if (options.fill) context.fill(); - context.stroke(); - }, - extendYRange : function (axis, data) { - this.max = Math.max(axis.max, this.max || -Number.MAX_VALUE); - } -}); diff --git a/addons/web_graph/static/lib/flotr2/js/types/timeline.js b/addons/web_graph/static/lib/flotr2/js/types/timeline.js deleted file mode 100644 index 59ea6094c01..00000000000 --- a/addons/web_graph/static/lib/flotr2/js/types/timeline.js +++ /dev/null @@ -1,90 +0,0 @@ -Flotr.addType('timeline', { - options: { - show: false, - lineWidth: 1, - barWidth: 0.2, - fill: true, - fillColor: null, - fillOpacity: 0.4, - centered: true - }, - - draw : function (options) { - - var - context = options.context; - - context.save(); - context.lineJoin = 'miter'; - context.lineWidth = options.lineWidth; - context.strokeStyle = options.color; - context.fillStyle = options.fillStyle; - - this.plot(options); - - context.restore(); - }, - - plot : function (options) { - - var - data = options.data, - context = options.context, - xScale = options.xScale, - yScale = options.yScale, - barWidth = options.barWidth, - lineWidth = options.lineWidth, - i; - - Flotr._.each(data, function (timeline) { - - var - x = timeline[0], - y = timeline[1], - w = timeline[2], - h = barWidth, - - xt = Math.ceil(xScale(x)), - wt = Math.ceil(xScale(x + w)) - xt, - yt = Math.round(yScale(y)), - ht = Math.round(yScale(y - h)) - yt, - - x0 = xt - lineWidth / 2, - y0 = Math.round(yt - ht / 2) - lineWidth / 2; - - context.strokeRect(x0, y0, wt, ht); - context.fillRect(x0, y0, wt, ht); - - }); - }, - - extendRange : function (series) { - - var - data = series.data, - xa = series.xaxis, - ya = series.yaxis, - w = series.timeline.barWidth; - - if (xa.options.min === null) - xa.min = xa.datamin - w / 2; - - if (xa.options.max === null) { - - var - max = xa.max; - - Flotr._.each(data, function (timeline) { - max = Math.max(max, timeline[0] + timeline[2]); - }, this); - - xa.max = max + w / 2; - } - - if (ya.options.min === null) - ya.min = ya.datamin - w; - if (ya.options.min === null) - ya.max = ya.datamax + w; - } - -}); diff --git a/addons/web_graph/static/lib/flotr2/lib/base64.js b/addons/web_graph/static/lib/flotr2/lib/base64.js deleted file mode 100644 index 3306e49f9f7..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/base64.js +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (C) 1999 Masanao Izumo - * Version: 1.0 - * LastModified: Dec 25 1999 - * This library is free. You can redistribute it and/or modify it. - */ - -/* - * Interfaces: - * b64 = base64encode(data); - * data = base64decode(b64); - */ - -(function() { - -var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -var base64DecodeChars = [ - -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]; - -function base64encode(str) { - var out, i, len; - var c1, c2, c3; - - len = str.length; - i = 0; - out = ""; - while(i < len) { - c1 = str.charCodeAt(i++) & 0xff; - if(i == len) - { - out += base64EncodeChars.charAt(c1 >> 2); - out += base64EncodeChars.charAt((c1 & 0x3) << 4); - out += "=="; - break; - } - c2 = str.charCodeAt(i++); - if(i == len) - { - out += base64EncodeChars.charAt(c1 >> 2); - out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); - out += base64EncodeChars.charAt((c2 & 0xF) << 2); - out += "="; - break; - } - c3 = str.charCodeAt(i++); - out += base64EncodeChars.charAt(c1 >> 2); - out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); - out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)); - out += base64EncodeChars.charAt(c3 & 0x3F); - } - return out; -} - -function base64decode(str) { - var c1, c2, c3, c4; - var i, len, out; - - len = str.length; - i = 0; - out = ""; - while(i < len) { - /* c1 */ - do { - c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; - } while(i < len && c1 == -1); - if(c1 == -1) - break; - - /* c2 */ - do { - c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff]; - } while(i < len && c2 == -1); - if(c2 == -1) - break; - - out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); - - /* c3 */ - do { - c3 = str.charCodeAt(i++) & 0xff; - if(c3 == 61) - return out; - c3 = base64DecodeChars[c3]; - } while(i < len && c3 == -1); - if(c3 == -1) - break; - - out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); - - /* c4 */ - do { - c4 = str.charCodeAt(i++) & 0xff; - if(c4 == 61) - return out; - c4 = base64DecodeChars[c4]; - } while(i < len && c4 == -1); - if(c4 == -1) - break; - out += String.fromCharCode(((c3 & 0x03) << 6) | c4); - } - return out; -} - -if (!window.btoa) window.btoa = base64encode; -if (!window.atob) window.atob = base64decode; - -})(); \ No newline at end of file diff --git a/addons/web_graph/static/lib/flotr2/lib/bean-min.js b/addons/web_graph/static/lib/flotr2/lib/bean-min.js deleted file mode 100644 index 2471420fe25..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/bean-min.js +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * bean.js - copyright Jacob Thornton 2011 - * https://github.com/fat/bean - * MIT License - * special thanks to: - * dean edwards: http://dean.edwards.name/ - * dperini: https://github.com/dperini/nwevents - * the entire mootools team: github.com/mootools/mootools-core - *//*global module:true, define:true*/ -!function(a,b,c){typeof module!="undefined"?module.exports=c(a,b):typeof define=="function"&&typeof define.amd=="object"?define(c):b[a]=c(a,b)}("bean",this,function(a,b){var c=window,d=b[a],e=/over|out/,f=/[^\.]*(?=\..*)\.|.*/,g=/\..*/,h="addEventListener",i="attachEvent",j="removeEventListener",k="detachEvent",l=document||{},m=l.documentElement||{},n=m[h],o=n?h:i,p=Array.prototype.slice,q=/click|mouse|menu|drag|drop/i,r=/^touch|^gesture/i,s={one:1},t=function(a,b,c){for(c=0;c0){b=b.split(" ");for(j=b.length;j--;)G(a,b[j],c);return a}h=l&&b.replace(g,""),h&&u[h]&&(h=u[h].type);if(!b||l){if(i=l&&b.replace(f,""))i=i.split(".");k(a,h,c,i)}else if(typeof b=="function")k(a,null,b);else for(d in b)b.hasOwnProperty(d)&&G(a,d,b[d]);return a},H=function(a,b,c,d,e){var f,g,h,i,j=c,k=c&&typeof c=="string";if(b&&!c&&typeof b=="object")for(f in b)b.hasOwnProperty(f)&&H.apply(this,[a,f,b[f]]);else{i=arguments.length>3?p.call(arguments,3):[],g=(k?c:b).split(" "),k&&(c=F(b,j=d,e))&&(i=p.call(i,1)),this===s&&(c=C(G,a,b,c,j));for(h=g.length;h--;)E(a,g[h],c,j,i)}return a},I=function(){return H.apply(s,arguments)},J=n?function(a,b,d){var e=l.createEvent(a?"HTMLEvents":"UIEvents");e[a?"initEvent":"initUIEvent"](b,!0,!0,c,1),d.dispatchEvent(e)}:function(a,b,c){c=w(c,a),a?c.fireEvent("on"+b,l.createEventObject()):c["_on"+b]++},K=function(a,b,c){var d,e,h,i,j,k=b.split(" ");for(d=k.length;d--;){b=k[d].replace(g,"");if(i=k[d].replace(f,""))i=i.split(".");if(!i&&!c&&a[o])J(t[b],b,a);else{j=y.get(a,b),c=[!1].concat(c);for(e=0,h=j.length;e 0) { - // remove(el, 't1 t2 t3', fn) or remove(el, 't1 t2 t3') - typeSpec = typeSpec.split(' ') - for (i = typeSpec.length; i--;) - remove(element, typeSpec[i], fn) - return element - } - type = isString && typeSpec.replace(nameRegex, '') - if (type && customEvents[type]) - type = customEvents[type].type - if (!typeSpec || isString) { - // remove(el) or remove(el, t1.ns) or remove(el, .ns) or remove(el, .ns1.ns2.ns3) - if (namespaces = isString && typeSpec.replace(namespaceRegex, '')) - namespaces = namespaces.split('.') - rm(element, type, fn, namespaces) - } else if (typeof typeSpec === 'function') { - // remove(el, fn) - rm(element, null, typeSpec) - } else { - // remove(el, { t1: fn1, t2, fn2 }) - for (k in typeSpec) { - if (typeSpec.hasOwnProperty(k)) - remove(element, k, typeSpec[k]) - } - } - return element - } - - , add = function (element, events, fn, delfn, $) { - var type, types, i, args - , originalFn = fn - , isDel = fn && typeof fn === 'string' - - if (events && !fn && typeof events === 'object') { - for (type in events) { - if (events.hasOwnProperty(type)) - add.apply(this, [ element, type, events[type] ]) - } - } else { - args = arguments.length > 3 ? slice.call(arguments, 3) : [] - types = (isDel ? fn : events).split(' ') - isDel && (fn = del(events, (originalFn = delfn), $)) && (args = slice.call(args, 1)) - // special case for one() - this === ONE && (fn = once(remove, element, events, fn, originalFn)) - for (i = types.length; i--;) addListener(element, types[i], fn, originalFn, args) - } - return element - } - - , one = function () { - return add.apply(ONE, arguments) - } - - , fireListener = W3C_MODEL ? function (isNative, type, element) { - var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents') - evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1) - element.dispatchEvent(evt) - } : function (isNative, type, element) { - element = targetElement(element, isNative) - // if not-native then we're using onpropertychange so we just increment a custom property - isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++ - } - - , fire = function (element, type, args) { - var i, j, l, names, handlers - , types = type.split(' ') - - for (i = types.length; i--;) { - type = types[i].replace(nameRegex, '') - if (names = types[i].replace(namespaceRegex, '')) - names = names.split('.') - if (!names && !args && element[eventSupport]) { - fireListener(nativeEvents[type], type, element) - } else { - // non-native event, either because of a namespace, arguments or a non DOM element - // iterate over all listeners and manually 'fire' - handlers = registry.get(element, type) - args = [false].concat(args) - for (j = 0, l = handlers.length; j < l; j++) { - if (handlers[j].inNamespaces(names)) - handlers[j].handler.apply(element, args) - } - } - } - return element - } - - , clone = function (element, from, type) { - var i = 0 - , handlers = registry.get(from, type) - , l = handlers.length - - for (;i < l; i++) - handlers[i].original && add(element, handlers[i].type, handlers[i].original) - return element - } - - , bean = { - add: add - , one: one - , remove: remove - , clone: clone - , fire: fire - , noConflict: function () { - context[name] = old - return this - } - } - - if (win[attachEvent]) { - // for IE, clean up on unload to avoid leaks - var cleanup = function () { - var i, entries = registry.entries() - for (i in entries) { - if (entries[i].type && entries[i].type !== 'unload') - remove(entries[i].element, entries[i].type) - } - win[detachEvent]('onunload', cleanup) - win.CollectGarbage && win.CollectGarbage() - } - win[attachEvent]('onunload', cleanup) - } - - return bean -}); diff --git a/addons/web_graph/static/lib/flotr2/lib/canvas2image.js b/addons/web_graph/static/lib/flotr2/lib/canvas2image.js deleted file mode 100644 index e064cdac8b9..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/canvas2image.js +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Canvas2Image v0.1 - * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com - * MIT License [http://www.opensource.org/licenses/mit-license.php] - */ - -var Canvas2Image = (function() { - // check if we have canvas support - var oCanvas = document.createElement("canvas"), - sc = String.fromCharCode, - strDownloadMime = "image/octet-stream", - bReplaceDownloadMime = false; - - // no canvas, bail out. - if (!oCanvas.getContext) { - return { - saveAsBMP : function(){}, - saveAsPNG : function(){}, - saveAsJPEG : function(){} - } - } - - var bHasImageData = !!(oCanvas.getContext("2d").getImageData), - bHasDataURL = !!(oCanvas.toDataURL), - bHasBase64 = !!(window.btoa); - - // ok, we're good - var readCanvasData = function(oCanvas) { - var iWidth = parseInt(oCanvas.width), - iHeight = parseInt(oCanvas.height); - return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight); - } - - // base64 encodes either a string or an array of charcodes - var encodeData = function(data) { - var i, aData, strData = ""; - - if (typeof data == "string") { - strData = data; - } else { - aData = data; - for (i = 0; i < aData.length; i++) { - strData += sc(aData[i]); - } - } - return btoa(strData); - } - - // creates a base64 encoded string containing BMP data takes an imagedata object as argument - var createBMP = function(oData) { - var strHeader = '', - iWidth = oData.width, - iHeight = oData.height; - - strHeader += 'BM'; - - var iFileSize = iWidth*iHeight*4 + 54; // total header size = 54 bytes - strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); - strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); - strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); - strHeader += sc(iFileSize % 256); - - strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset - strHeader += sc(40, 0, 0, 0); // info header size - - var iImageWidth = iWidth; - strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); - strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); - strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); - strHeader += sc(iImageWidth % 256); - - var iImageHeight = iHeight; - strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); - strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); - strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); - strHeader += sc(iImageHeight % 256); - - strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel - strHeader += sc(0, 0, 0, 0); // compression = none - - var iDataSize = iWidth*iHeight*4; - strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); - strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); - strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); - strHeader += sc(iDataSize % 256); - - strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used - - var aImgData = oData.data, - strPixelData = "", - c, x, y = iHeight, - iOffsetX, iOffsetY, strPixelRow; - - do { - iOffsetY = iWidth*(y-1)*4; - strPixelRow = ""; - for (x = 0; x < iWidth; x++) { - iOffsetX = 4*x; - strPixelRow += sc( - aImgData[iOffsetY + iOffsetX + 2], // B - aImgData[iOffsetY + iOffsetX + 1], // G - aImgData[iOffsetY + iOffsetX], // R - aImgData[iOffsetY + iOffsetX + 3] // A - ); - } - strPixelData += strPixelRow; - } while (--y); - - return encodeData(strHeader + strPixelData); - } - - // sends the generated file to the client - var saveFile = function(strData) { - if (!window.open(strData)) { - document.location.href = strData; - } - } - - var makeDataURI = function(strData, strMime) { - return "data:" + strMime + ";base64," + strData; - } - - // generates a object containing the imagedata - var makeImageObject = function(strSource) { - var oImgElement = document.createElement("img"); - oImgElement.src = strSource; - return oImgElement; - } - - var scaleCanvas = function(oCanvas, iWidth, iHeight) { - if (iWidth && iHeight) { - var oSaveCanvas = document.createElement("canvas"); - - oSaveCanvas.width = iWidth; - oSaveCanvas.height = iHeight; - oSaveCanvas.style.width = iWidth+"px"; - oSaveCanvas.style.height = iHeight+"px"; - - var oSaveCtx = oSaveCanvas.getContext("2d"); - - oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth); - - return oSaveCanvas; - } - return oCanvas; - } - - return { - saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) { - if (!bHasDataURL) return false; - - var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight), - strMime = "image/png", - strData = oScaledCanvas.toDataURL(strMime); - - if (bReturnImg) { - return makeImageObject(strData); - } else { - saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData); - } - return true; - }, - - saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) { - if (!bHasDataURL) return false; - - var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight), - strMime = "image/jpeg", - strData = oScaledCanvas.toDataURL(strMime); - - // check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false - if (strData.indexOf(strMime) != 5) return false; - - if (bReturnImg) { - return makeImageObject(strData); - } else { - saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData); - } - return true; - }, - - saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) { - if (!(bHasDataURL && bHasImageData && bHasBase64)) return false; - - var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight), - strMime = "image/bmp", - oData = readCanvasData(oScaledCanvas), - strImgData = createBMP(oData); - - if (bReturnImg) { - return makeImageObject(makeDataURI(strImgData, strMime)); - } else { - saveFile(makeDataURI(strImgData, strMime)); - } - return true; - } - }; -})(); \ No newline at end of file diff --git a/addons/web_graph/static/lib/flotr2/lib/canvastext.js b/addons/web_graph/static/lib/flotr2/lib/canvastext.js deleted file mode 100644 index 2df45bae0d8..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/canvastext.js +++ /dev/null @@ -1,429 +0,0 @@ -/** - * This code is released to the public domain by Jim Studt, 2007. - * He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/ - * It as been modified by Fabien Ménager to handle font style like size, weight, color and rotation. - * A partial support for special characters has been added too. - */ -var CanvasText = { - /** The letters definition. It is a list of letters, - * with their width, and the coordinates of points compositing them. - * The syntax for the points is : [x, y], null value means "pen up" - */ - 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]] }, - - // Lower case Latin-1 - 'à': { 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' }, - - // Upper case Latin-1 - 'À': { 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, used to draw accentuated letters */ - 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]] } - }, - - /** The default font styling */ - style: { - size: 8, // font height in pixels - font: null, // not yet implemented - color: '#000000', // font color - weight: 1, // float, 1 for 'normal' - textAlign: 'left', // left, right, center - textBaseline: 'bottom', // top, middle, bottom - adjustAlign: false, // modifies the alignments if the angle is different from 0 to make the spin point always at the good position - angle: 0, // in radians, anticlockwise - tracking: 1, // space between the letters, float, 1 for 'normal' - boundingBoxColor: '#ff0000', // color of the bounding box (null to hide), can be used for debug and font drawing - originPointColor: '#000000' // color of the bounding box (null to hide), can be used for debug and font drawing - }, - - debug: false, - _bufferLexemes: {}, - - extend: function(dest, src) { - for (var property in src) { - if (property in dest) continue; - dest[property] = src[property]; - } - return dest; - }, - - /** Get the letter data corresponding to a char - * @param {String} ch - The char - */ - letter: function(ch) { - return CanvasText.letters[ch]; - }, - - parseLexemes: function(str) { - if (CanvasText._bufferLexemes[str]) - return CanvasText._bufferLexemes[str]; - - var i, c, matches = str.match(/&[A-Za-z]{2,5};|\s|./g), - result = [], chars = []; - - for (i = 0; i < matches.length; i++) { - c = matches[i]; - if (c.length == 1) - chars.push(c); - else { - var entity = c.substring(1, c.length-1); - if (CanvasText.specialchars[entity]) - chars.push(entity); - else - chars = chars.concat(c.toArray()); - } - } - for (i = 0; i < chars.length; i++) { - c = chars[i]; - if (c = CanvasText.letters[c] || CanvasText.specialchars[c]) result.push(c); - } - for (i = 0; i < result.length; i++) { - if (result === null || typeof result === 'undefined') - delete result[i]; - } - return CanvasText._bufferLexemes[str] = result; - }, - - /** Get the font ascent for a given style - * @param {Object} style - The reference style - */ - ascent: function(style) { - style = style || CanvasText.style; - return (style.size || CanvasText.style.size); - }, - - /** Get the font descent for a given style - * @param {Object} style - The reference style - * */ - descent: function(style) { - style = style || CanvasText.style; - return 7.0*(style.size || CanvasText.style.size)/25.0; - }, - - /** Measure the text horizontal size - * @param {String} str - The text - * @param {Object} style - Text style - * */ - measure: function(str, style) { - if (!str) return; - style = style || CanvasText.style; - - var i, width, lexemes = CanvasText.parseLexemes(str), - total = 0; - - for (i = lexemes.length-1; i > -1; --i) { - c = lexemes[i]; - width = (c.diacritic) ? CanvasText.letter(c.letter).width : c.width; - total += width * (style.tracking || CanvasText.style.tracking) * (style.size || CanvasText.style.size) / 25.0; - } - return total; - }, - - getDimensions: function(str, style) { - style = style || CanvasText.style; - - var width = CanvasText.measure(str, style), - height = style.size || CanvasText.style.size, - angle = style.angle || CanvasText.style.angle; - - if (style.angle == 0) return {width: width, height: height}; - return { - width: Math.abs(Math.cos(angle) * width) + Math.abs(Math.sin(angle) * height), - height: Math.abs(Math.sin(angle) * width) + Math.abs(Math.cos(angle) * height) - } - }, - - /** Draws serie of points at given coordinates - * @param {Canvas context} ctx - The canvas context - * @param {Array} points - The points to draw - * @param {Number} x - The X coordinate - * @param {Number} y - The Y coordinate - * @param {Number} mag - The scale - */ - drawPoints: function (ctx, points, x, y, mag, offset) { - var i, a, penUp = true, needStroke = 0; - offset = offset || {x:0, y:0}; - - ctx.beginPath(); - for (i = 0; i < points.length; i++) { - a = points[i]; - if (!a) { - penUp = true; - continue; - } - if (penUp) { - ctx.moveTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y); - penUp = false; - } - else { - ctx.lineTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y); - } - } - ctx.stroke(); - ctx.closePath(); - }, - - /** Draws a text at given coordinates and with a given style - * @param {String} str - The text to draw - * @param {Number} xOrig - The X coordinate - * @param {Number} yOrig - The Y coordinate - * @param {Object} style - The font style - */ - draw: function(str, xOrig, yOrig, style) { - if (!str) return; - CanvasText.extend(style, CanvasText.style); - - var i, c, total = 0, - mag = style.size / 25.0, - x = 0, y = 0, - lexemes = CanvasText.parseLexemes(str), - offset = {x: 0, y: 0}, - measure = CanvasText.measure(str, style), - align; - - if (style.adjustAlign) { - align = CanvasText.getBestAlign(style.angle, style); - CanvasText.extend(style, align); - } - - switch (style.textAlign) { - case 'left': break; - case 'center': offset.x = -measure / 2; break; - case 'right': offset.x = -measure; break; - } - - switch (style.textBaseline) { - case 'bottom': break; - case 'middle': offset.y = style.size / 2; break; - case 'top': offset.y = style.size; break; - } - - this.save(); - this.translate(xOrig, yOrig); - this.rotate(style.angle); - this.lineCap = "round"; - this.lineWidth = 2.0 * mag * (style.weight || CanvasText.style.weight); - this.strokeStyle = style.color || CanvasText.style.color; - - for (i = 0; i < lexemes.length; i++) { - c = lexemes[i]; - if (c.width == -1) { - x = 0; - y = style.size * 1.4; - continue; - } - - var points = c.points, - width = c.width; - - if (c.diacritic) { - var dia = CanvasText.diacritics[c.diacritic], - character = CanvasText.letter(c.letter); - - CanvasText.drawPoints(this, dia.points, x, y - (c.letter.toUpperCase() == c.letter ? 3 : 0), mag, offset); - points = character.points; - width = character.width; - } - - CanvasText.drawPoints(this, points, x, y, mag, offset); - - if (CanvasText.debug) { - this.save(); - this.lineJoin = "miter"; - this.lineWidth = 0.5; - this.strokeStyle = (style.boundingBoxColor || CanvasText.style.boundingBoxColor); - this.strokeRect(x+offset.x, y+offset.y, width*mag, -style.size); - - this.fillStyle = (style.originPointColor || CanvasText.style.originPointColor); - this.beginPath(); - this.arc(0, 0, 1.5, 0, Math.PI*2, true); - this.fill(); - this.closePath(); - this.restore(); - } - - x += width*mag*(style.tracking || CanvasText.style.tracking); - } - this.restore(); - return total; - } -}; - -/** The text functions are bound to the CanvasRenderingContext2D prototype */ -CanvasText.proto = window.CanvasRenderingContext2D ? window.CanvasRenderingContext2D.prototype : document.createElement('canvas').getContext('2d').__proto__; - -if (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; -} \ No newline at end of file diff --git a/addons/web_graph/static/lib/flotr2/lib/excanvas.js b/addons/web_graph/static/lib/flotr2/lib/excanvas.js deleted file mode 100644 index 005bab1186f..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/excanvas.js +++ /dev/null @@ -1,1425 +0,0 @@ -// Copyright 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -// Known Issues: -// -// * Patterns only support repeat. -// * Radial gradient are not implemented. The VML version of these look very -// different from the canvas one. -// * Clipping paths are not implemented. -// * Coordsize. The width and height attribute have higher priority than the -// width and height style values which isn't correct. -// * Painting mode isn't implemented. -// * Canvas width/height should is using content-box by default. IE in -// Quirks mode will draw the canvas using border-box. Either change your -// doctype to HTML5 -// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) -// or use Box Sizing Behavior from WebFX -// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) -// * Non uniform scaling does not correctly scale strokes. -// * Optimize. There is always room for speed improvements. - -// Only add this code if we do not already have a canvas implementation -if (!document.createElement('canvas').getContext) { - -(function() { - - // alias some functions to make (compiled) code shorter - var m = Math; - var mr = m.round; - var ms = m.sin; - var mc = m.cos; - var abs = m.abs; - var sqrt = m.sqrt; - - // this is used for sub pixel precision - var Z = 10; - var Z2 = Z / 2; - - var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1]; - - /** - * This funtion is assigned to the elements as element.getContext(). - * @this {HTMLElement} - * @return {CanvasRenderingContext2D_} - */ - function getContext() { - return this.context_ || - (this.context_ = new CanvasRenderingContext2D_(this)); - } - - var slice = Array.prototype.slice; - - /** - * Binds a function to an object. The returned function will always use the - * passed in {@code obj} as {@code this}. - * - * Example: - * - * g = bind(f, obj, a, b) - * g(c, d) // will do f.call(obj, a, b, c, d) - * - * @param {Function} f The function to bind the object to - * @param {Object} obj The object that should act as this when the function - * is called - * @param {*} var_args Rest arguments that will be used as the initial - * arguments when the function is called - * @return {Function} A new function that has bound this - */ - function bind(f, obj, var_args) { - var a = slice.call(arguments, 2); - return function() { - return f.apply(obj, a.concat(slice.call(arguments))); - }; - } - - function encodeHtmlAttribute(s) { - return String(s).replace(/&/g, '&').replace(/"/g, '"'); - } - - function addNamespace(doc, prefix, urn) { - if (!doc.namespaces[prefix]) { - doc.namespaces.add(prefix, urn, '#default#VML'); - } - } - - function addNamespacesAndStylesheet(doc) { - addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml'); - addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office'); - - // Setup default CSS. Only add one style sheet per document - if (!doc.styleSheets['ex_canvas_']) { - var ss = doc.createStyleSheet(); - ss.owningElement.id = 'ex_canvas_'; - ss.cssText = 'canvas{display:inline-block;overflow:hidden;' + - // default size is 300x150 in Gecko and Opera - 'text-align:left;width:300px;height:150px}'; - } - } - - // Add namespaces and stylesheet at startup. - addNamespacesAndStylesheet(document); - - var G_vmlCanvasManager_ = { - init: function(opt_doc) { - var doc = opt_doc || document; - // Create a dummy element so that IE will allow canvas elements to be - // recognized. - doc.createElement('canvas'); - doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); - }, - - init_: function(doc) { - // find all canvas elements - var els = doc.getElementsByTagName('canvas'); - for (var i = 0; i < els.length; i++) { - this.initElement(els[i]); - } - }, - - /** - * Public initializes a canvas element so that it can be used as canvas - * element from now on. This is called automatically before the page is - * loaded but if you are creating elements using createElement you need to - * make sure this is called on the element. - * @param {HTMLElement} el The canvas element to initialize. - * @return {HTMLElement} the element that was created. - */ - initElement: function(el) { - if (!el.getContext) { - el.getContext = getContext; - - // Add namespaces and stylesheet to document of the element. - addNamespacesAndStylesheet(el.ownerDocument); - - // Remove fallback content. There is no way to hide text nodes so we - // just remove all childNodes. We could hide all elements and remove - // text nodes but who really cares about the fallback content. - el.innerHTML = ''; - - // do not use inline function because that will leak memory - el.attachEvent('onpropertychange', onPropertyChange); - el.attachEvent('onresize', onResize); - - var attrs = el.attributes; - if (attrs.width && attrs.width.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setWidth_(attrs.width.nodeValue); - el.style.width = attrs.width.nodeValue + 'px'; - } else { - el.width = el.clientWidth; - } - if (attrs.height && attrs.height.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setHeight_(attrs.height.nodeValue); - el.style.height = attrs.height.nodeValue + 'px'; - } else { - el.height = el.clientHeight; - } - //el.getContext().setCoordsize_() - } - return el; - } - }; - - function onPropertyChange(e) { - var el = e.srcElement; - - switch (e.propertyName) { - case 'width': - el.getContext().clearRect(); - el.style.width = el.attributes.width.nodeValue + 'px'; - // In IE8 this does not trigger onresize. - if (el.firstChild) { - el.firstChild.style.width = el.clientWidth + 'px'; - } - break; - case 'height': - el.getContext().clearRect(); - el.style.height = el.attributes.height.nodeValue + 'px'; - if (el.firstChild) { - el.firstChild.style.height = el.clientHeight + 'px'; - } - break; - } - } - - function onResize(e) { - var el = e.srcElement; - if (el.firstChild) { - el.firstChild.style.width = el.clientWidth + 'px'; - el.firstChild.style.height = el.clientHeight + 'px'; - } - } - - G_vmlCanvasManager_.init(); - - // precompute "00" to "FF" - var decToHex = []; - for (var i = 0; i < 16; i++) { - for (var j = 0; j < 16; j++) { - decToHex[i * 16 + j] = i.toString(16) + j.toString(16); - } - } - - function createMatrixIdentity() { - return [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ]; - } - - function matrixMultiply(m1, m2) { - var result = createMatrixIdentity(); - - for (var x = 0; x < 3; x++) { - for (var y = 0; y < 3; y++) { - var sum = 0; - - for (var z = 0; z < 3; z++) { - sum += m1[x][z] * m2[z][y]; - } - - result[x][y] = sum; - } - } - return result; - } - - function copyState(o1, o2) { - o2.fillStyle = o1.fillStyle; - o2.lineCap = o1.lineCap; - o2.lineJoin = o1.lineJoin; - o2.lineWidth = o1.lineWidth; - o2.miterLimit = o1.miterLimit; - o2.shadowBlur = o1.shadowBlur; - o2.shadowColor = o1.shadowColor; - o2.shadowOffsetX = o1.shadowOffsetX; - o2.shadowOffsetY = o1.shadowOffsetY; - o2.strokeStyle = o1.strokeStyle; - o2.globalAlpha = o1.globalAlpha; - o2.font = o1.font; - o2.textAlign = o1.textAlign; - o2.textBaseline = o1.textBaseline; - o2.arcScaleX_ = o1.arcScaleX_; - o2.arcScaleY_ = o1.arcScaleY_; - o2.lineScale_ = o1.lineScale_; - } - - var colorData = { - 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' - }; - - - function getRgbHslContent(styleString) { - var start = styleString.indexOf('(', 3); - var end = styleString.indexOf(')', start + 1); - var parts = styleString.substring(start + 1, end).split(','); - // add alpha if needed - if (parts.length != 4 || styleString.charAt(3) != 'a') { - parts[3] = 1; - } - return parts; - } - - function percent(s) { - return parseFloat(s) / 100; - } - - function clamp(v, min, max) { - return Math.min(max, Math.max(min, v)); - } - - function hslToRgb(parts){ - var r, g, b, h, s, l; - h = parseFloat(parts[0]) / 360 % 360; - if (h < 0) - h++; - s = clamp(percent(parts[1]), 0, 1); - l = clamp(percent(parts[2]), 0, 1); - if (s == 0) { - r = g = b = l; // achromatic - } else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hueToRgb(p, q, h + 1 / 3); - g = hueToRgb(p, q, h); - b = hueToRgb(p, q, h - 1 / 3); - } - - return '#' + decToHex[Math.floor(r * 255)] + - decToHex[Math.floor(g * 255)] + - decToHex[Math.floor(b * 255)]; - } - - function hueToRgb(m1, m2, h) { - if (h < 0) - h++; - if (h > 1) - h--; - - if (6 * h < 1) - return m1 + (m2 - m1) * 6 * h; - else if (2 * h < 1) - return m2; - else if (3 * h < 2) - return m1 + (m2 - m1) * (2 / 3 - h) * 6; - else - return m1; - } - - var processStyleCache = {}; - - function processStyle(styleString) { - if (styleString in processStyleCache) { - return processStyleCache[styleString]; - } - - var str, alpha = 1; - - styleString = String(styleString); - if (styleString.charAt(0) == '#') { - str = styleString; - } else if (/^rgb/.test(styleString)) { - var parts = getRgbHslContent(styleString); - var str = '#', n; - for (var i = 0; i < 3; i++) { - if (parts[i].indexOf('%') != -1) { - n = Math.floor(percent(parts[i]) * 255); - } else { - n = +parts[i]; - } - str += decToHex[clamp(n, 0, 255)]; - } - alpha = +parts[3]; - } else if (/^hsl/.test(styleString)) { - var parts = getRgbHslContent(styleString); - str = hslToRgb(parts); - alpha = parts[3]; - } else { - str = colorData[styleString] || styleString; - } - return processStyleCache[styleString] = {color: str, alpha: alpha}; - } - - var DEFAULT_STYLE = { - style: 'normal', - variant: 'normal', - weight: 'normal', - size: 10, - family: 'sans-serif' - }; - - // Internal text style cache - var fontStyleCache = {}; - - function processFontStyle(styleString) { - if (fontStyleCache[styleString]) { - return fontStyleCache[styleString]; - } - - var el = document.createElement('div'); - var style = el.style; - try { - style.font = styleString; - } catch (ex) { - // Ignore failures to set to invalid font. - } - - return fontStyleCache[styleString] = { - style: style.fontStyle || DEFAULT_STYLE.style, - variant: style.fontVariant || DEFAULT_STYLE.variant, - weight: style.fontWeight || DEFAULT_STYLE.weight, - size: style.fontSize || DEFAULT_STYLE.size, - family: style.fontFamily || DEFAULT_STYLE.family - }; - } - - function getComputedStyle(style, element) { - var computedStyle = {}; - - for (var p in style) { - computedStyle[p] = style[p]; - } - - // Compute the size - var canvasFontSize = parseFloat(element.currentStyle.fontSize), - fontSize = parseFloat(style.size); - - if (typeof style.size == 'number') { - computedStyle.size = style.size; - } else if (style.size.indexOf('px') != -1) { - computedStyle.size = fontSize; - } else if (style.size.indexOf('em') != -1) { - computedStyle.size = canvasFontSize * fontSize; - } else if(style.size.indexOf('%') != -1) { - computedStyle.size = (canvasFontSize / 100) * fontSize; - } else if (style.size.indexOf('pt') != -1) { - computedStyle.size = fontSize / .75; - } else { - computedStyle.size = canvasFontSize; - } - - // Different scaling between normal text and VML text. This was found using - // trial and error to get the same size as non VML text. - //computedStyle.size *= 0.981; - - return computedStyle; - } - - function buildStyle(style) { - return style.style + ' ' + style.variant + ' ' + style.weight + ' ' + - style.size + 'px ' + style.family; - } - - var lineCapMap = { - 'butt': 'flat', - 'round': 'round' - }; - - function processLineCap(lineCap) { - return lineCapMap[lineCap] || 'square'; - } - - /** - * This class implements CanvasRenderingContext2D interface as described by - * the WHATWG. - * @param {HTMLElement} canvasElement The element that the 2D context should - * be associated with - */ - function CanvasRenderingContext2D_(canvasElement) { - this.m_ = createMatrixIdentity(); - - this.mStack_ = []; - this.aStack_ = []; - this.currentPath_ = []; - - // Canvas context properties - this.strokeStyle = '#000'; - this.fillStyle = '#000'; - - this.lineWidth = 1; - this.lineJoin = 'miter'; - this.lineCap = 'butt'; - this.miterLimit = Z * 1; - this.globalAlpha = 1; - this.font = '10px sans-serif'; - this.textAlign = 'left'; - this.textBaseline = 'alphabetic'; - this.canvas = canvasElement; - - var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' + - canvasElement.clientHeight + 'px;overflow:hidden;position:absolute'; - var el = canvasElement.ownerDocument.createElement('div'); - el.style.cssText = cssText; - canvasElement.appendChild(el); - - var overlayEl = el.cloneNode(false); - // Use a non transparent background. - overlayEl.style.backgroundColor = 'red'; - overlayEl.style.filter = 'alpha(opacity=0)'; - canvasElement.appendChild(overlayEl); - - this.element_ = el; - this.arcScaleX_ = 1; - this.arcScaleY_ = 1; - this.lineScale_ = 1; - } - - var contextPrototype = CanvasRenderingContext2D_.prototype; - contextPrototype.clearRect = function() { - if (this.textMeasureEl_) { - this.textMeasureEl_.removeNode(true); - this.textMeasureEl_ = null; - } - this.element_.innerHTML = ''; - }; - - contextPrototype.beginPath = function() { - // TODO: Branch current matrix so that save/restore has no effect - // as per safari docs. - this.currentPath_ = []; - }; - - contextPrototype.moveTo = function(aX, aY) { - var p = getCoords(this, aX, aY); - this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y}); - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.lineTo = function(aX, aY) { - var p = getCoords(this, aX, aY); - this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y}); - - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY) { - var p = getCoords(this, aX, aY); - var cp1 = getCoords(this, aCP1x, aCP1y); - var cp2 = getCoords(this, aCP2x, aCP2y); - bezierCurveTo(this, cp1, cp2, p); - }; - - // Helper function that takes the already fixed cordinates. - function bezierCurveTo(self, cp1, cp2, p) { - self.currentPath_.push({ - type: 'bezierCurveTo', - cp1x: cp1.x, - cp1y: cp1.y, - cp2x: cp2.x, - cp2y: cp2.y, - x: p.x, - y: p.y - }); - self.currentX_ = p.x; - self.currentY_ = p.y; - } - - contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { - // the following is lifted almost directly from - // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes - - var cp = getCoords(this, aCPx, aCPy); - var p = getCoords(this, aX, aY); - - var cp1 = { - x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), - y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_) - }; - var cp2 = { - x: cp1.x + (p.x - this.currentX_) / 3.0, - y: cp1.y + (p.y - this.currentY_) / 3.0 - }; - - bezierCurveTo(this, cp1, cp2, p); - }; - - contextPrototype.arc = function(aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise) { - aRadius *= Z; - var arcType = aClockwise ? 'at' : 'wa'; - - var xStart = aX + mc(aStartAngle) * aRadius - Z2; - var yStart = aY + ms(aStartAngle) * aRadius - Z2; - - var xEnd = aX + mc(aEndAngle) * aRadius - Z2; - var yEnd = aY + ms(aEndAngle) * aRadius - Z2; - - // IE won't render arches drawn counter clockwise if xStart == xEnd. - if ((abs(xStart - xEnd) < 10e-8) && !aClockwise) { - xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something - // that can be represented in binary - } - // IE won't render arches drawn clockwise if yStart is very close to yEnd. - if ((abs(yStart - yEnd) < 10e-8) && aClockwise) { - yStart -= 0.125; // Offset yStart by 1/80 of a pixel. Use something - // that can be represented in binary - } - - var p = getCoords(this, aX, aY); - var pStart = getCoords(this, xStart, yStart); - var pEnd = getCoords(this, xEnd, yEnd); - - this.currentPath_.push({type: arcType, - x: p.x, - y: p.y, - radius: aRadius, - xStart: pStart.x, - yStart: pStart.y, - xEnd: pEnd.x, - yEnd: pEnd.y}); - - }; - - contextPrototype.rect = function(aX, aY, aWidth, aHeight) { - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - }; - - contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.stroke(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.fill(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { - var gradient = new CanvasGradient_('gradient'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - return gradient; - }; - - contextPrototype.createRadialGradient = function(aX0, aY0, aR0, - aX1, aY1, aR1) { - var gradient = new CanvasGradient_('gradientradial'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.r0_ = aR0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - gradient.r1_ = aR1; - return gradient; - }; - - contextPrototype.drawImage = function(image, var_args) { - var dx, dy, dw, dh, sx, sy, sw, sh; - - // to find the original width we overide the width and height - var oldRuntimeWidth = image.runtimeStyle.width; - var oldRuntimeHeight = image.runtimeStyle.height; - image.runtimeStyle.width = 'auto'; - image.runtimeStyle.height = 'auto'; - - // get the original size - var w = image.width; - var h = image.height; - - // and remove overides - image.runtimeStyle.width = oldRuntimeWidth; - image.runtimeStyle.height = oldRuntimeHeight; - - if (arguments.length == 3) { - dx = arguments[1]; - dy = arguments[2]; - sx = sy = 0; - sw = dw = w; - sh = dh = h; - } else if (arguments.length == 5) { - dx = arguments[1]; - dy = arguments[2]; - dw = arguments[3]; - dh = arguments[4]; - sx = sy = 0; - sw = w; - sh = h; - } else if (arguments.length == 9) { - sx = arguments[1]; - sy = arguments[2]; - sw = arguments[3]; - sh = arguments[4]; - dx = arguments[5]; - dy = arguments[6]; - dw = arguments[7]; - dh = arguments[8]; - } else { - throw Error('Invalid number of arguments'); - } - - var d = getCoords(this, dx, dy); - - var w2 = sw / 2; - var h2 = sh / 2; - - var vmlStr = []; - - var W = 10; - var H = 10; - - // For some reason that I've now forgotten, using divs didn't work - vmlStr.push(' ' , - '', - ''); - - this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join('')); - }; - - contextPrototype.stroke = function(aFill) { - var lineStr = []; - var lineOpen = false; - - var W = 10; - var H = 10; - - lineStr.push(''); - - if (!aFill) { - appendStroke(this, lineStr); - } else { - appendFill(this, lineStr, min, max); - } - - lineStr.push(''); - - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); - }; - - function appendStroke(ctx, lineStr) { - var a = processStyle(ctx.strokeStyle); - var color = a.color; - var opacity = a.alpha * ctx.globalAlpha; - var lineWidth = ctx.lineScale_ * ctx.lineWidth; - - // VML cannot correctly render a line if the width is less than 1px. - // In that case, we dilute the color to make the line look thinner. - if (lineWidth < 1) { - opacity *= lineWidth; - } - - lineStr.push( - '' - ); - } - - function appendFill(ctx, lineStr, min, max) { - var fillStyle = ctx.fillStyle; - var arcScaleX = ctx.arcScaleX_; - var arcScaleY = ctx.arcScaleY_; - var width = max.x - min.x; - var height = max.y - min.y; - if (fillStyle instanceof CanvasGradient_) { - // TODO: Gradients transformed with the transformation matrix. - var angle = 0; - var focus = {x: 0, y: 0}; - - // additional offset - var shift = 0; - // scale factor for offset - var expansion = 1; - - if (fillStyle.type_ == 'gradient') { - var x0 = fillStyle.x0_ / arcScaleX; - var y0 = fillStyle.y0_ / arcScaleY; - var x1 = fillStyle.x1_ / arcScaleX; - var y1 = fillStyle.y1_ / arcScaleY; - var p0 = getCoords(ctx, x0, y0); - var p1 = getCoords(ctx, x1, y1); - var dx = p1.x - p0.x; - var dy = p1.y - p0.y; - angle = Math.atan2(dx, dy) * 180 / Math.PI; - - // The angle should be a non-negative number. - if (angle < 0) { - angle += 360; - } - - // Very small angles produce an unexpected result because they are - // converted to a scientific notation string. - if (angle < 1e-6) { - angle = 0; - } - } else { - var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_); - focus = { - x: (p0.x - min.x) / width, - y: (p0.y - min.y) / height - }; - - width /= arcScaleX * Z; - height /= arcScaleY * Z; - var dimension = m.max(width, height); - shift = 2 * fillStyle.r0_ / dimension; - expansion = 2 * fillStyle.r1_ / dimension - shift; - } - - // We need to sort the color stops in ascending order by offset, - // otherwise IE won't interpret it correctly. - var stops = fillStyle.colors_; - stops.sort(function(cs1, cs2) { - return cs1.offset - cs2.offset; - }); - - var length = stops.length; - var color1 = stops[0].color; - var color2 = stops[length - 1].color; - var opacity1 = stops[0].alpha * ctx.globalAlpha; - var opacity2 = stops[length - 1].alpha * ctx.globalAlpha; - - var colors = []; - for (var i = 0; i < length; i++) { - var stop = stops[i]; - colors.push(stop.offset * expansion + shift + ' ' + stop.color); - } - - // When colors attribute is used, the meanings of opacity and o:opacity2 - // are reversed. - lineStr.push(''); - } else if (fillStyle instanceof CanvasPattern_) { - if (width && height) { - var deltaLeft = -min.x; - var deltaTop = -min.y; - lineStr.push(''); - } - } else { - var a = processStyle(ctx.fillStyle); - var color = a.color; - var opacity = a.alpha * ctx.globalAlpha; - lineStr.push(''); - } - } - - contextPrototype.fill = function() { - this.stroke(true); - }; - - contextPrototype.closePath = function() { - this.currentPath_.push({type: 'close'}); - }; - - function getCoords(ctx, aX, aY) { - var m = ctx.m_; - return { - x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, - y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 - }; - }; - - contextPrototype.save = function() { - var o = {}; - copyState(this, o); - this.aStack_.push(o); - this.mStack_.push(this.m_); - this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); - }; - - contextPrototype.restore = function() { - if (this.aStack_.length) { - copyState(this.aStack_.pop(), this); - this.m_ = this.mStack_.pop(); - } - }; - - function matrixIsFinite(m) { - return isFinite(m[0][0]) && isFinite(m[0][1]) && - isFinite(m[1][0]) && isFinite(m[1][1]) && - isFinite(m[2][0]) && isFinite(m[2][1]); - } - - function setM(ctx, m, updateLineScale) { - if (!matrixIsFinite(m)) { - return; - } - ctx.m_ = m; - - if (updateLineScale) { - // Get the line scale. - // Determinant of this.m_ means how much the area is enlarged by the - // transformation. So its square root can be used as a scale factor - // for width. - var det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; - ctx.lineScale_ = sqrt(abs(det)); - } - } - - contextPrototype.translate = function(aX, aY) { - var m1 = [ - [1, 0, 0], - [0, 1, 0], - [aX, aY, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.rotate = function(aRot) { - var c = mc(aRot); - var s = ms(aRot); - - var m1 = [ - [c, s, 0], - [-s, c, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.scale = function(aX, aY) { - this.arcScaleX_ *= aX; - this.arcScaleY_ *= aY; - var m1 = [ - [aX, 0, 0], - [0, aY, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) { - var m1 = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) { - var m = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, m, true); - }; - - /** - * The text drawing function. - * The maxWidth argument isn't taken in account, since no browser supports - * it yet. - */ - contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) { - var m = this.m_, - delta = 1000, - left = 0, - right = delta, - offset = {x: 0, y: 0}, - lineStr = []; - - var fontStyle = getComputedStyle(processFontStyle(this.font), - this.element_); - - var fontStyleString = buildStyle(fontStyle); - - var elementStyle = this.element_.currentStyle; - var textAlign = this.textAlign.toLowerCase(); - switch (textAlign) { - case 'left': - case 'center': - case 'right': - break; - case 'end': - textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left'; - break; - case 'start': - textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left'; - break; - default: - textAlign = 'left'; - } - - // 1.75 is an arbitrary number, as there is no info about the text baseline - switch (this.textBaseline) { - case 'hanging': - case 'top': - offset.y = fontStyle.size / 1.75; - break; - case 'middle': - break; - default: - case null: - case 'alphabetic': - case 'ideographic': - case 'bottom': - offset.y = -fontStyle.size / 2.25; - break; - } - - switch(textAlign) { - case 'right': - left = delta; - right = 0.05; - break; - case 'center': - left = right = delta / 2; - break; - } - - var d = getCoords(this, x + offset.x, y + offset.y); - - lineStr.push(''); - - if (stroke) { - appendStroke(this, lineStr); - } else { - // TODO: Fix the min and max params. - appendFill(this, lineStr, {x: -left, y: 0}, - {x: right, y: fontStyle.size}); - } - - var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' + - m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0'; - - var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z); - - lineStr.push('', - '', - ''); - - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); - }; - - contextPrototype.fillText = function(text, x, y, maxWidth) { - this.drawText_(text, x, y, maxWidth, false); - }; - - contextPrototype.strokeText = function(text, x, y, maxWidth) { - this.drawText_(text, x, y, maxWidth, true); - }; - - contextPrototype.measureText = function(text) { - if (!this.textMeasureEl_) { - var s = ''; - this.element_.insertAdjacentHTML('beforeEnd', s); - this.textMeasureEl_ = this.element_.lastChild; - } - var doc = this.element_.ownerDocument; - this.textMeasureEl_.innerHTML = ''; - this.textMeasureEl_.style.font = this.font; - // Don't use innerHTML or innerText because they allow markup/whitespace. - this.textMeasureEl_.appendChild(doc.createTextNode(text)); - return {width: this.textMeasureEl_.offsetWidth}; - }; - - /******** STUBS ********/ - contextPrototype.clip = function() { - // TODO: Implement - }; - - contextPrototype.arcTo = function() { - // TODO: Implement - }; - - contextPrototype.createPattern = function(image, repetition) { - return new CanvasPattern_(image, repetition); - }; - - // Gradient / Pattern Stubs - function CanvasGradient_(aType) { - this.type_ = aType; - this.x0_ = 0; - this.y0_ = 0; - this.r0_ = 0; - this.x1_ = 0; - this.y1_ = 0; - this.r1_ = 0; - this.colors_ = []; - } - - CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { - aColor = processStyle(aColor); - this.colors_.push({offset: aOffset, - color: aColor.color, - alpha: aColor.alpha}); - }; - - function CanvasPattern_(image, repetition) { - assertImageIsValid(image); - switch (repetition) { - case 'repeat': - case null: - case '': - this.repetition_ = 'repeat'; - break - case 'repeat-x': - case 'repeat-y': - case 'no-repeat': - this.repetition_ = repetition; - break; - default: - throwException('SYNTAX_ERR'); - } - - this.src_ = image.src; - this.width_ = image.width; - this.height_ = image.height; - } - - function throwException(s) { - throw new DOMException_(s); - } - - function assertImageIsValid(img) { - if (!img || img.nodeType != 1 || img.tagName != 'IMG') { - throwException('TYPE_MISMATCH_ERR'); - } - if (img.readyState != 'complete') { - throwException('INVALID_STATE_ERR'); - } - } - - function DOMException_(s) { - this.code = this[s]; - this.message = s +': DOM Exception ' + this.code; - } - var p = DOMException_.prototype = new Error; - p.INDEX_SIZE_ERR = 1; - p.DOMSTRING_SIZE_ERR = 2; - p.HIERARCHY_REQUEST_ERR = 3; - p.WRONG_DOCUMENT_ERR = 4; - p.INVALID_CHARACTER_ERR = 5; - p.NO_DATA_ALLOWED_ERR = 6; - p.NO_MODIFICATION_ALLOWED_ERR = 7; - p.NOT_FOUND_ERR = 8; - p.NOT_SUPPORTED_ERR = 9; - p.INUSE_ATTRIBUTE_ERR = 10; - p.INVALID_STATE_ERR = 11; - p.SYNTAX_ERR = 12; - p.INVALID_MODIFICATION_ERR = 13; - p.NAMESPACE_ERR = 14; - p.INVALID_ACCESS_ERR = 15; - p.VALIDATION_ERR = 16; - p.TYPE_MISMATCH_ERR = 17; - - // set up externs - G_vmlCanvasManager = G_vmlCanvasManager_; - CanvasRenderingContext2D = CanvasRenderingContext2D_; - CanvasGradient = CanvasGradient_; - CanvasPattern = CanvasPattern_; - DOMException = DOMException_; -})(); - -} // if diff --git a/addons/web_graph/static/lib/flotr2/lib/imagediff.js b/addons/web_graph/static/lib/flotr2/lib/imagediff.js deleted file mode 100644 index ac1d2745018..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/imagediff.js +++ /dev/null @@ -1,343 +0,0 @@ -/*! imagediff.js 1.0.2 - * (c) 2011 Carl Sutherland, Humble Software Development - * imagediff.js is freely distributable under the MIT license. - * Thanks to Jacob Thornton for the node/amd integration bits. - * For details and documentation: - * https://github.com/HumbleSoftware/js-imagediff - */ -(function (name, definition) { - var root = this; - if (typeof module != 'undefined') { - module.exports = definition(); - } else if (typeof define == 'function' && typeof define.amd == 'object') { - define(definition); - } else { - root[name] = definition(root, name); - } -})('imagediff', function (root, name) { - - var - TYPE_ARRAY = '[object Array]', - TYPE_CANVAS = '[object HTMLCanvasElement]', - TYPE_CONTEXT = '[object CanvasRenderingContext2D]', - TYPE_IMAGE = '[object HTMLImageElement]', - - OBJECT = 'object', - UNDEFINED = 'undefined', - - canvas = getCanvas(), - context = canvas.getContext('2d'), - previous = root[name], - imagediff, jasmine; - - // Creation - function getCanvas (width, height) { - var - canvas = document.createElement('canvas'); - if (width) canvas.width = width; - if (height) canvas.height = height; - return canvas; - } - function getImageData (width, height) { - canvas.width = width; - canvas.height = height; - context.clearRect(0, 0, width, height); - return context.createImageData(width, height); - } - - - // Type Checking - function isImage (object) { - return isType(object, TYPE_IMAGE); - } - function isCanvas (object) { - return isType(object, TYPE_CANVAS); - } - function isContext (object) { - return isType(object, TYPE_CONTEXT); - } - function isImageData (object) { - var - imageData = getImageData(1, 1); - isImageData = function (object) { - return (object && imageData.constructor === object.constructor ? true : false); - }; - return isImageData(object); - } - function isImageType (object) { - return ( - isImage(object) || - isCanvas(object) || - isContext(object) || - isImageData(object) - ); - } - function isType (object, type) { - return typeof (object) === 'object' && Object.prototype.toString.apply(object) === type; - } - - - // Type Conversion - function copyImageData (imageData) { - var - height = imageData.height, - width = imageData.width; - canvas.width = width; - canvas.height = height; - context.putImageData(imageData, 0, 0); - return context.getImageData(0, 0, width, height); - } - function toImageData (object) { - if (isImage(object)) { return toImageDataFromImage(object); } - if (isCanvas(object)) { return toImageDataFromCanvas(object); } - if (isContext(object)) { return toImageDataFromContext(object); } - if (isImageData(object)) { return object; } - } - function toImageDataFromImage (image) { - var - height = image.height, - width = image.width; - canvas.width = width; - canvas.height = height; - context.clearRect(0, 0, width, height); - context.drawImage(image, 0, 0); - return context.getImageData(0, 0, width, height); - } - function toImageDataFromCanvas (canvas) { - var - height = canvas.height, - width = canvas.width, - context = canvas.getContext('2d'); - return context.getImageData(0, 0, width, height); - } - function toImageDataFromContext (context) { - var - canvas = context.canvas, - height = canvas.height, - width = canvas.width; - return context.getImageData(0, 0, width, height); - } - function toCanvas (object) { - var - data = toImageData(object), - canvas = getCanvas(data.width, data.height), - context = canvas.getContext('2d'); - - context.putImageData(data, 0, 0); - return canvas; - } - - - // ImageData Equality Operators - function equalWidth (a, b) { - return a.width === b.width; - } - function equalHeight (a, b) { - return a.height === b.height; - } - function equalDimensions (a, b) { - return equalHeight(a, b) && equalWidth(a, b); - } - function equal (a, b, tolerance) { - - var - aData = a.data, - bData = b.data, - length = aData.length, - tolerance = tolerance || 0, - i; - - if (!equalDimensions(a, b)) return false; - for (i = length; i--;) if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > tolerance) return false; - - return true; - } - - - // Diff - function diff (a, b) { - return (equalDimensions(a, b) ? diffEqual : diffUnequal)(a, b); - } - function diffEqual (a, b) { - - var - height = a.height, - width = a.width, - c = getImageData(width, height), // c = a - b - aData = a.data, - bData = b.data, - cData = c.data, - length = cData.length, - row, column, - i, j, k, v; - - for (i = 0; i < length; i += 4) { - cData[i] = Math.abs(aData[i] - bData[i]); - cData[i+1] = Math.abs(aData[i+1] - bData[i+1]); - cData[i+2] = Math.abs(aData[i+2] - bData[i+2]); - cData[i+3] = Math.abs(255 - aData[i+3] - bData[i+3]); - } - - return c; - } - function diffUnequal (a, b) { - - var - height = Math.max(a.height, b.height), - width = Math.max(a.width, b.width), - c = getImageData(width, height), // c = a - b - aData = a.data, - bData = b.data, - cData = c.data, - rowOffset, - columnOffset, - row, column, - i, j, k, v; - - - for (i = cData.length - 1; i > 0; i = i - 4) { - cData[i] = 255; - } - - // Add First Image - offsets(a); - for (row = a.height; row--;){ - for (column = a.width; column--;) { - i = 4 * ((row + rowOffset) * width + (column + columnOffset)); - j = 4 * (row * a.width + column); - cData[i+0] = aData[j+0]; // r - cData[i+1] = aData[j+1]; // g - cData[i+2] = aData[j+2]; // b - // cData[i+3] = aData[j+3]; // a - } - } - - // Subtract Second Image - offsets(b); - for (row = b.height; row--;){ - for (column = b.width; column--;) { - i = 4 * ((row + rowOffset) * width + (column + columnOffset)); - j = 4 * (row * b.width + column); - cData[i+0] = Math.abs(cData[i+0] - bData[j+0]); // r - cData[i+1] = Math.abs(cData[i+1] - bData[j+1]); // g - cData[i+2] = Math.abs(cData[i+2] - bData[j+2]); // b - } - } - - // Helpers - function offsets (imageData) { - rowOffset = Math.floor((height - imageData.height) / 2); - columnOffset = Math.floor((width - imageData.width) / 2); - } - - return c; - } - - - // Validation - function checkType () { - var i; - for (i = 0; i < arguments.length; i++) { - if (!isImageType(arguments[i])) { - throw { - name : 'ImageTypeError', - message : 'Submitted object was not an image.' - }; - } - } - } - - - // Jasmine Matchers - function get (element, content) { - element = document.createElement(element); - if (element && content) { - element.innerHTML = content; - } - return element; - } - jasmine = { - - toBeImageData : function () { - return imagediff.isImageData(this.actual); - }, - - toImageDiffEqual : function (expected, tolerance) { - - this.message = function() { - - var - div = get('div'), - a = get('div', '
    Actual:
    '), - b = get('div', '
    Expected:
    '), - c = get('div', '
    Diff:
    '), - diff = imagediff.diff(this.actual, expected), - canvas = getCanvas(), - context; - - canvas.height = diff.height; - canvas.width = diff.width; - - context = canvas.getContext('2d'); - context.putImageData(diff, 0, 0); - - a.appendChild(toCanvas(this.actual)); - b.appendChild(toCanvas(expected)); - c.appendChild(canvas); - - div.appendChild(a); - div.appendChild(b); - div.appendChild(c); - - return [ - div, - "Expected not to be equal." - ]; - }; - - return imagediff.equal(this.actual, expected, tolerance); - } - }; - - // Definition - imagediff = { - - createCanvas : getCanvas, - createImageData : getImageData, - - isImage : isImage, - isCanvas : isCanvas, - isContext : isContext, - isImageData : isImageData, - isImageType : isImageType, - - toImageData : function (object) { - checkType(object); - if (isImageData(object)) { return copyImageData(object); } - return toImageData(object); - }, - - equal : function (a, b, tolerance) { - checkType(a, b); - a = toImageData(a); - b = toImageData(b); - return equal(a, b, tolerance); - }, - diff : function (a, b) { - checkType(a, b); - a = toImageData(a); - b = toImageData(b); - return diff(a, b); - }, - - jasmine : jasmine, - - // Compatibility - noConflict : function () { - root[name] = previous; - return imagediff; - } - }; - - return imagediff; -}); diff --git a/addons/web_graph/static/lib/flotr2/lib/jasmine/MIT.LICENSE b/addons/web_graph/static/lib/flotr2/lib/jasmine/MIT.LICENSE deleted file mode 100644 index 7c435baaec8..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/jasmine/MIT.LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2008-2011 Pivotal Labs - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine-html.js b/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine-html.js deleted file mode 100644 index 73834010f60..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine-html.js +++ /dev/null @@ -1,190 +0,0 @@ -jasmine.TrivialReporter = function(doc) { - this.document = doc || document; - this.suiteDivs = {}; - this.logRunningSpecs = false; -}; - -jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { - var el = document.createElement(type); - - for (var i = 2; i < arguments.length; i++) { - var child = arguments[i]; - - if (typeof child === 'string') { - el.appendChild(document.createTextNode(child)); - } else { - if (child) { el.appendChild(child); } - } - } - - for (var attr in attrs) { - if (attr == "className") { - el[attr] = attrs[attr]; - } else { - el.setAttribute(attr, attrs[attr]); - } - } - - return el; -}; - -jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { - var showPassed, showSkipped; - - this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' }, - this.createDom('div', { className: 'banner' }, - this.createDom('div', { className: 'logo' }, - this.createDom('span', { className: 'title' }, "Jasmine"), - this.createDom('span', { className: 'version' }, runner.env.versionString())), - this.createDom('div', { className: 'options' }, - "Show ", - showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), - this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), - showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), - this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") - ) - ), - - this.runnerDiv = this.createDom('div', { className: 'runner running' }, - this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), - this.runnerMessageSpan = this.createDom('span', {}, "Running..."), - this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) - ); - - this.document.body.appendChild(this.outerDiv); - - var suites = runner.suites(); - for (var i = 0; i < suites.length; i++) { - var suite = suites[i]; - var suiteDiv = this.createDom('div', { className: 'suite' }, - this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), - this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); - this.suiteDivs[suite.id] = suiteDiv; - var parentDiv = this.outerDiv; - if (suite.parentSuite) { - parentDiv = this.suiteDivs[suite.parentSuite.id]; - } - parentDiv.appendChild(suiteDiv); - } - - this.startedAt = new Date(); - - var self = this; - showPassed.onclick = function(evt) { - if (showPassed.checked) { - self.outerDiv.className += ' show-passed'; - } else { - self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); - } - }; - - showSkipped.onclick = function(evt) { - if (showSkipped.checked) { - self.outerDiv.className += ' show-skipped'; - } else { - self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); - } - }; -}; - -jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { - var results = runner.results(); - var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; - this.runnerDiv.setAttribute("class", className); - //do it twice for IE - this.runnerDiv.setAttribute("className", className); - var specs = runner.specs(); - var specCount = 0; - for (var i = 0; i < specs.length; i++) { - if (this.specFilter(specs[i])) { - specCount++; - } - } - var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); - message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; - this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); - - this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); -}; - -jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { - var results = suite.results(); - var status = results.passed() ? 'passed' : 'failed'; - if (results.totalCount === 0) { // todo: change this to check results.skipped - status = 'skipped'; - } - this.suiteDivs[suite.id].className += " " + status; -}; - -jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { - if (this.logRunningSpecs) { - this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); - } -}; - -jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { - var results = spec.results(); - var status = results.passed() ? 'passed' : 'failed'; - if (results.skipped) { - status = 'skipped'; - } - var specDiv = this.createDom('div', { className: 'spec ' + status }, - this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), - this.createDom('a', { - className: 'description', - href: '?spec=' + encodeURIComponent(spec.getFullName()), - title: spec.getFullName() - }, spec.description)); - - - var resultItems = results.getItems(); - var messagesDiv = this.createDom('div', { className: 'messages' }); - for (var i = 0; i < resultItems.length; i++) { - var result = resultItems[i]; - - if (result.type == 'log') { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && result.passed && !result.passed()) { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); - - if (result.trace.stack) { - messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); - } - } - } - - if (messagesDiv.childNodes.length > 0) { - specDiv.appendChild(messagesDiv); - } - - this.suiteDivs[spec.suite.id].appendChild(specDiv); -}; - -jasmine.TrivialReporter.prototype.log = function() { - var console = jasmine.getGlobal().console; - if (console && console.log) { - if (console.log.apply) { - console.log.apply(console, arguments); - } else { - console.log(arguments); // ie fix: console.log.apply doesn't exist on ie - } - } -}; - -jasmine.TrivialReporter.prototype.getLocation = function() { - return this.document.location; -}; - -jasmine.TrivialReporter.prototype.specFilter = function(spec) { - var paramMap = {}; - var params = this.getLocation().search.substring(1).split('&'); - for (var i = 0; i < params.length; i++) { - var p = params[i].split('='); - paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); - } - - if (!paramMap.spec) { - return true; - } - return spec.getFullName().indexOf(paramMap.spec) === 0; -}; diff --git a/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.css b/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.css deleted file mode 100644 index 6583fe7c66d..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.css +++ /dev/null @@ -1,166 +0,0 @@ -body { - font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; -} - - -.jasmine_reporter a:visited, .jasmine_reporter a { - color: #303; -} - -.jasmine_reporter a:hover, .jasmine_reporter a:active { - color: blue; -} - -.run_spec { - float:right; - padding-right: 5px; - font-size: .8em; - text-decoration: none; -} - -.jasmine_reporter { - margin: 0 5px; -} - -.banner { - color: #303; - background-color: #fef; - padding: 5px; -} - -.logo { - float: left; - font-size: 1.1em; - padding-left: 5px; -} - -.logo .version { - font-size: .6em; - padding-left: 1em; -} - -.runner.running { - background-color: yellow; -} - - -.options { - text-align: right; - font-size: .8em; -} - - - - -.suite { - border: 1px outset gray; - margin: 5px 0; - padding-left: 1em; -} - -.suite .suite { - margin: 5px; -} - -.suite.passed { - background-color: #dfd; -} - -.suite.failed { - background-color: #fdd; -} - -.spec { - margin: 5px; - padding-left: 1em; - clear: both; -} - -.spec.failed, .spec.passed, .spec.skipped { - padding-bottom: 5px; - border: 1px solid gray; -} - -.spec.failed { - background-color: #fbb; - border-color: red; -} - -.spec.passed { - background-color: #bfb; - border-color: green; -} - -.spec.skipped { - background-color: #bbb; -} - -.messages { - border-left: 1px dashed gray; - padding-left: 1em; - padding-right: 1em; -} - -.passed { - background-color: #cfc; - display: none; -} - -.failed { - background-color: #fbb; -} - -.skipped { - color: #777; - background-color: #eee; - display: none; -} - - -/*.resultMessage {*/ - /*white-space: pre;*/ -/*}*/ - -.resultMessage span.result { - display: block; - line-height: 2em; - color: black; -} - -.resultMessage .mismatch { - color: black; -} - -.stackTrace { - white-space: pre; - font-size: .8em; - margin-left: 10px; - max-height: 5em; - overflow: auto; - border: 1px inset red; - padding: 1em; - background: #eef; -} - -.finished-at { - padding-left: 1em; - font-size: .6em; -} - -.show-passed .passed, -.show-skipped .skipped { - display: block; -} - - -#jasmine_content { - position:fixed; - right: 100%; -} - -.runner { - border: 1px solid gray; - display: block; - margin: 5px 0; - padding: 2px 0 2px 10px; -} diff --git a/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.js b/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.js deleted file mode 100644 index c3d2dc7d2d3..00000000000 --- a/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.js +++ /dev/null @@ -1,2476 +0,0 @@ -var isCommonJS = typeof window == "undefined"; - -/** - * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. - * - * @namespace - */ -var jasmine = {}; -if (isCommonJS) exports.jasmine = jasmine; -/** - * @private - */ -jasmine.unimplementedMethod_ = function() { - throw new Error("unimplemented method"); -}; - -/** - * Use jasmine.undefined instead of undefined, since undefined is just - * a plain old variable and may be redefined by somebody else. - * - * @private - */ -jasmine.undefined = jasmine.___undefined___; - -/** - * Show diagnostic messages in the console if set to true - * - */ -jasmine.VERBOSE = false; - -/** - * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. - * - */ -jasmine.DEFAULT_UPDATE_INTERVAL = 250; - -/** - * Default timeout interval in milliseconds for waitsFor() blocks. - */ -jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; - -jasmine.getGlobal = function() { - function getGlobal() { - return this; - } - - return getGlobal(); -}; - -/** - * Allows for bound functions to be compared. Internal use only. - * - * @ignore - * @private - * @param base {Object} bound 'this' for the function - * @param name {Function} function to find - */ -jasmine.bindOriginal_ = function(base, name) { - var original = base[name]; - if (original.apply) { - return function() { - return original.apply(base, arguments); - }; - } else { - // IE support - return jasmine.getGlobal()[name]; - } -}; - -jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); -jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); -jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); -jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); - -jasmine.MessageResult = function(values) { - this.type = 'log'; - this.values = values; - this.trace = new Error(); // todo: test better -}; - -jasmine.MessageResult.prototype.toString = function() { - var text = ""; - for (var i = 0; i < this.values.length; i++) { - if (i > 0) text += " "; - if (jasmine.isString_(this.values[i])) { - text += this.values[i]; - } else { - text += jasmine.pp(this.values[i]); - } - } - return text; -}; - -jasmine.ExpectationResult = function(params) { - this.type = 'expect'; - this.matcherName = params.matcherName; - this.passed_ = params.passed; - this.expected = params.expected; - this.actual = params.actual; - this.message = this.passed_ ? 'Passed.' : params.message; - - var trace = (params.trace || new Error(this.message)); - this.trace = this.passed_ ? '' : trace; -}; - -jasmine.ExpectationResult.prototype.toString = function () { - return this.message; -}; - -jasmine.ExpectationResult.prototype.passed = function () { - return this.passed_; -}; - -/** - * Getter for the Jasmine environment. Ensures one gets created - */ -jasmine.getEnv = function() { - var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); - return env; -}; - -/** - * @ignore - * @private - * @param value - * @returns {Boolean} - */ -jasmine.isArray_ = function(value) { - return jasmine.isA_("Array", value); -}; - -/** - * @ignore - * @private - * @param value - * @returns {Boolean} - */ -jasmine.isString_ = function(value) { - return jasmine.isA_("String", value); -}; - -/** - * @ignore - * @private - * @param value - * @returns {Boolean} - */ -jasmine.isNumber_ = function(value) { - return jasmine.isA_("Number", value); -}; - -/** - * @ignore - * @private - * @param {String} typeName - * @param value - * @returns {Boolean} - */ -jasmine.isA_ = function(typeName, value) { - return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; -}; - -/** - * Pretty printer for expecations. Takes any object and turns it into a human-readable string. - * - * @param value {Object} an object to be outputted - * @returns {String} - */ -jasmine.pp = function(value) { - var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); - stringPrettyPrinter.format(value); - return stringPrettyPrinter.string; -}; - -/** - * Returns true if the object is a DOM Node. - * - * @param {Object} obj object to check - * @returns {Boolean} - */ -jasmine.isDomNode = function(obj) { - return obj.nodeType > 0; -}; - -/** - * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. - * - * @example - * // don't care about which function is passed in, as long as it's a function - * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function)); - * - * @param {Class} clazz - * @returns matchable object of the type clazz - */ -jasmine.any = function(clazz) { - return new jasmine.Matchers.Any(clazz); -}; - -/** - * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. - * - * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine - * expectation syntax. Spies can be checked if they were called or not and what the calling params were. - * - * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs). - * - * Spies are torn down at the end of every spec. - * - * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. - * - * @example - * // a stub - * var myStub = jasmine.createSpy('myStub'); // can be used anywhere - * - * // spy example - * var foo = { - * not: function(bool) { return !bool; } - * } - * - * // actual foo.not will not be called, execution stops - * spyOn(foo, 'not'); - - // foo.not spied upon, execution will continue to implementation - * spyOn(foo, 'not').andCallThrough(); - * - * // fake example - * var foo = { - * not: function(bool) { return !bool; } - * } - * - * // foo.not(val) will return val - * spyOn(foo, 'not').andCallFake(function(value) {return value;}); - * - * // mock example - * foo.not(7 == 7); - * expect(foo.not).toHaveBeenCalled(); - * expect(foo.not).toHaveBeenCalledWith(true); - * - * @constructor - * @see spyOn, jasmine.createSpy, jasmine.createSpyObj - * @param {String} name - */ -jasmine.Spy = function(name) { - /** - * The name of the spy, if provided. - */ - this.identity = name || 'unknown'; - /** - * Is this Object a spy? - */ - this.isSpy = true; - /** - * The actual function this spy stubs. - */ - this.plan = function() { - }; - /** - * Tracking of the most recent call to the spy. - * @example - * var mySpy = jasmine.createSpy('foo'); - * mySpy(1, 2); - * mySpy.mostRecentCall.args = [1, 2]; - */ - this.mostRecentCall = {}; - - /** - * Holds arguments for each call to the spy, indexed by call count - * @example - * var mySpy = jasmine.createSpy('foo'); - * mySpy(1, 2); - * mySpy(7, 8); - * mySpy.mostRecentCall.args = [7, 8]; - * mySpy.argsForCall[0] = [1, 2]; - * mySpy.argsForCall[1] = [7, 8]; - */ - this.argsForCall = []; - this.calls = []; -}; - -/** - * Tells a spy to call through to the actual implemenatation. - * - * @example - * var foo = { - * bar: function() { // do some stuff } - * } - * - * // defining a spy on an existing property: foo.bar - * spyOn(foo, 'bar').andCallThrough(); - */ -jasmine.Spy.prototype.andCallThrough = function() { - this.plan = this.originalValue; - return this; -}; - -/** - * For setting the return value of a spy. - * - * @example - * // defining a spy from scratch: foo() returns 'baz' - * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); - * - * // defining a spy on an existing property: foo.bar() returns 'baz' - * spyOn(foo, 'bar').andReturn('baz'); - * - * @param {Object} value - */ -jasmine.Spy.prototype.andReturn = function(value) { - this.plan = function() { - return value; - }; - return this; -}; - -/** - * For throwing an exception when a spy is called. - * - * @example - * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' - * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); - * - * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' - * spyOn(foo, 'bar').andThrow('baz'); - * - * @param {String} exceptionMsg - */ -jasmine.Spy.prototype.andThrow = function(exceptionMsg) { - this.plan = function() { - throw exceptionMsg; - }; - return this; -}; - -/** - * Calls an alternate implementation when a spy is called. - * - * @example - * var baz = function() { - * // do some stuff, return something - * } - * // defining a spy from scratch: foo() calls the function baz - * var foo = jasmine.createSpy('spy on foo').andCall(baz); - * - * // defining a spy on an existing property: foo.bar() calls an anonymnous function - * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); - * - * @param {Function} fakeFunc - */ -jasmine.Spy.prototype.andCallFake = function(fakeFunc) { - this.plan = fakeFunc; - return this; -}; - -/** - * Resets all of a spy's the tracking variables so that it can be used again. - * - * @example - * spyOn(foo, 'bar'); - * - * foo.bar(); - * - * expect(foo.bar.callCount).toEqual(1); - * - * foo.bar.reset(); - * - * expect(foo.bar.callCount).toEqual(0); - */ -jasmine.Spy.prototype.reset = function() { - this.wasCalled = false; - this.callCount = 0; - this.argsForCall = []; - this.calls = []; - this.mostRecentCall = {}; -}; - -jasmine.createSpy = function(name) { - - var spyObj = function() { - spyObj.wasCalled = true; - spyObj.callCount++; - var args = jasmine.util.argsToArray(arguments); - spyObj.mostRecentCall.object = this; - spyObj.mostRecentCall.args = args; - spyObj.argsForCall.push(args); - spyObj.calls.push({object: this, args: args}); - return spyObj.plan.apply(this, arguments); - }; - - var spy = new jasmine.Spy(name); - - for (var prop in spy) { - spyObj[prop] = spy[prop]; - } - - spyObj.reset(); - - return spyObj; -}; - -/** - * Determines whether an object is a spy. - * - * @param {jasmine.Spy|Object} putativeSpy - * @returns {Boolean} - */ -jasmine.isSpy = function(putativeSpy) { - return putativeSpy && putativeSpy.isSpy; -}; - -/** - * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something - * large in one call. - * - * @param {String} baseName name of spy class - * @param {Array} methodNames array of names of methods to make spies - */ -jasmine.createSpyObj = function(baseName, methodNames) { - if (!jasmine.isArray_(methodNames) || methodNames.length === 0) { - throw new Error('createSpyObj requires a non-empty array of method names to create spies for'); - } - var obj = {}; - for (var i = 0; i < methodNames.length; i++) { - obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); - } - return obj; -}; - -/** - * All parameters are pretty-printed and concatenated together, then written to the current spec's output. - * - * Be careful not to leave calls to jasmine.log in production code. - */ -jasmine.log = function() { - var spec = jasmine.getEnv().currentSpec; - spec.log.apply(spec, arguments); -}; - -/** - * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. - * - * @example - * // spy example - * var foo = { - * not: function(bool) { return !bool; } - * } - * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops - * - * @see jasmine.createSpy - * @param obj - * @param methodName - * @returns a Jasmine spy that can be chained with all spy methods - */ -var spyOn = function(obj, methodName) { - return jasmine.getEnv().currentSpec.spyOn(obj, methodName); -}; -if (isCommonJS) exports.spyOn = spyOn; - -/** - * Creates a Jasmine spec that will be added to the current suite. - * - * // TODO: pending tests - * - * @example - * it('should be true', function() { - * expect(true).toEqual(true); - * }); - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var it = function(desc, func) { - return jasmine.getEnv().it(desc, func); -}; -if (isCommonJS) exports.it = it; - -/** - * Creates a disabled Jasmine spec. - * - * A convenience method that allows existing specs to be disabled temporarily during development. - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var xit = function(desc, func) { - return jasmine.getEnv().xit(desc, func); -}; -if (isCommonJS) exports.xit = xit; - -/** - * Starts a chain for a Jasmine expectation. - * - * It is passed an Object that is the actual value and should chain to one of the many - * jasmine.Matchers functions. - * - * @param {Object} actual Actual value to test against and expected value - */ -var expect = function(actual) { - return jasmine.getEnv().currentSpec.expect(actual); -}; -if (isCommonJS) exports.expect = expect; - -/** - * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. - * - * @param {Function} func Function that defines part of a jasmine spec. - */ -var runs = function(func) { - jasmine.getEnv().currentSpec.runs(func); -}; -if (isCommonJS) exports.runs = runs; - -/** - * Waits a fixed time period before moving to the next block. - * - * @deprecated Use waitsFor() instead - * @param {Number} timeout milliseconds to wait - */ -var waits = function(timeout) { - jasmine.getEnv().currentSpec.waits(timeout); -}; -if (isCommonJS) exports.waits = waits; - -/** - * Waits for the latchFunction to return true before proceeding to the next block. - * - * @param {Function} latchFunction - * @param {String} optional_timeoutMessage - * @param {Number} optional_timeout - */ -var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { - jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); -}; -if (isCommonJS) exports.waitsFor = waitsFor; - -/** - * A function that is called before each spec in a suite. - * - * Used for spec setup, including validating assumptions. - * - * @param {Function} beforeEachFunction - */ -var beforeEach = function(beforeEachFunction) { - jasmine.getEnv().beforeEach(beforeEachFunction); -}; -if (isCommonJS) exports.beforeEach = beforeEach; - -/** - * A function that is called after each spec in a suite. - * - * Used for restoring any state that is hijacked during spec execution. - * - * @param {Function} afterEachFunction - */ -var afterEach = function(afterEachFunction) { - jasmine.getEnv().afterEach(afterEachFunction); -}; -if (isCommonJS) exports.afterEach = afterEach; - -/** - * Defines a suite of specifications. - * - * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared - * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization - * of setup in some tests. - * - * @example - * // TODO: a simple suite - * - * // TODO: a simple suite with a nested describe block - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var describe = function(description, specDefinitions) { - return jasmine.getEnv().describe(description, specDefinitions); -}; -if (isCommonJS) exports.describe = describe; - -/** - * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var xdescribe = function(description, specDefinitions) { - return jasmine.getEnv().xdescribe(description, specDefinitions); -}; -if (isCommonJS) exports.xdescribe = xdescribe; - - -// Provide the XMLHttpRequest class for IE 5.x-6.x: -jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { - function tryIt(f) { - try { - return f(); - } catch(e) { - } - return null; - } - - var xhr = tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.6.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.3.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP"); - }) || - tryIt(function() { - return new ActiveXObject("Microsoft.XMLHTTP"); - }); - - if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); - - return xhr; -} : XMLHttpRequest; -/** - * @namespace - */ -jasmine.util = {}; - -/** - * Declare that a child class inherit it's prototype from the parent class. - * - * @private - * @param {Function} childClass - * @param {Function} parentClass - */ -jasmine.util.inherit = function(childClass, parentClass) { - /** - * @private - */ - var subclass = function() { - }; - subclass.prototype = parentClass.prototype; - childClass.prototype = new subclass(); -}; - -jasmine.util.formatException = function(e) { - var lineNumber; - if (e.line) { - lineNumber = e.line; - } - else if (e.lineNumber) { - lineNumber = e.lineNumber; - } - - var file; - - if (e.sourceURL) { - file = e.sourceURL; - } - else if (e.fileName) { - file = e.fileName; - } - - var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); - - if (file && lineNumber) { - message += ' in ' + file + ' (line ' + lineNumber + ')'; - } - - return message; -}; - -jasmine.util.htmlEscape = function(str) { - if (!str) return str; - return str.replace(/&/g, '&') - .replace(//g, '>'); -}; - -jasmine.util.argsToArray = function(args) { - var arrayOfArgs = []; - for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); - return arrayOfArgs; -}; - -jasmine.util.extend = function(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; -}; - -/** - * Environment for Jasmine - * - * @constructor - */ -jasmine.Env = function() { - this.currentSpec = null; - this.currentSuite = null; - this.currentRunner_ = new jasmine.Runner(this); - - this.reporter = new jasmine.MultiReporter(); - - this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; - this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; - this.lastUpdate = 0; - this.specFilter = function() { - return true; - }; - - this.nextSpecId_ = 0; - this.nextSuiteId_ = 0; - this.equalityTesters_ = []; - - // wrap matchers - this.matchersClass = function() { - jasmine.Matchers.apply(this, arguments); - }; - jasmine.util.inherit(this.matchersClass, jasmine.Matchers); - - jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); -}; - - -jasmine.Env.prototype.setTimeout = jasmine.setTimeout; -jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; -jasmine.Env.prototype.setInterval = jasmine.setInterval; -jasmine.Env.prototype.clearInterval = jasmine.clearInterval; - -/** - * @returns an object containing jasmine version build info, if set. - */ -jasmine.Env.prototype.version = function () { - if (jasmine.version_) { - return jasmine.version_; - } else { - throw new Error('Version not set'); - } -}; - -/** - * @returns string containing jasmine version build info, if set. - */ -jasmine.Env.prototype.versionString = function() { - if (!jasmine.version_) { - return "version unknown"; - } - - var version = this.version(); - var versionString = version.major + "." + version.minor + "." + version.build; - if (version.release_candidate) { - versionString += ".rc" + version.release_candidate; - } - versionString += " revision " + version.revision; - return versionString; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSpecId = function () { - return this.nextSpecId_++; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSuiteId = function () { - return this.nextSuiteId_++; -}; - -/** - * Register a reporter to receive status updates from Jasmine. - * @param {jasmine.Reporter} reporter An object which will receive status updates. - */ -jasmine.Env.prototype.addReporter = function(reporter) { - this.reporter.addReporter(reporter); -}; - -jasmine.Env.prototype.execute = function() { - this.currentRunner_.execute(); -}; - -jasmine.Env.prototype.describe = function(description, specDefinitions) { - var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); - - var parentSuite = this.currentSuite; - if (parentSuite) { - parentSuite.add(suite); - } else { - this.currentRunner_.add(suite); - } - - this.currentSuite = suite; - - var declarationError = null; - try { - specDefinitions.call(suite); - } catch(e) { - declarationError = e; - } - - if (declarationError) { - this.it("encountered a declaration exception", function() { - throw declarationError; - }); - } - - this.currentSuite = parentSuite; - - return suite; -}; - -jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { - if (this.currentSuite) { - this.currentSuite.beforeEach(beforeEachFunction); - } else { - this.currentRunner_.beforeEach(beforeEachFunction); - } -}; - -jasmine.Env.prototype.currentRunner = function () { - return this.currentRunner_; -}; - -jasmine.Env.prototype.afterEach = function(afterEachFunction) { - if (this.currentSuite) { - this.currentSuite.afterEach(afterEachFunction); - } else { - this.currentRunner_.afterEach(afterEachFunction); - } - -}; - -jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { - return { - execute: function() { - } - }; -}; - -jasmine.Env.prototype.it = function(description, func) { - var spec = new jasmine.Spec(this, this.currentSuite, description); - this.currentSuite.add(spec); - this.currentSpec = spec; - - if (func) { - spec.runs(func); - } - - return spec; -}; - -jasmine.Env.prototype.xit = function(desc, func) { - return { - id: this.nextSpecId(), - runs: function() { - } - }; -}; - -jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { - if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { - return true; - } - - a.__Jasmine_been_here_before__ = b; - b.__Jasmine_been_here_before__ = a; - - var hasKey = function(obj, keyName) { - return obj !== null && obj[keyName] !== jasmine.undefined; - }; - - for (var property in b) { - if (!hasKey(a, property) && hasKey(b, property)) { - mismatchKeys.push("expected has key '" + property + "', but missing from actual."); - } - } - for (property in a) { - if (!hasKey(b, property) && hasKey(a, property)) { - mismatchKeys.push("expected missing key '" + property + "', but present in actual."); - } - } - for (property in b) { - if (property == '__Jasmine_been_here_before__') continue; - if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { - mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); - } - } - - if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { - mismatchValues.push("arrays were not the same length"); - } - - delete a.__Jasmine_been_here_before__; - delete b.__Jasmine_been_here_before__; - return (mismatchKeys.length === 0 && mismatchValues.length === 0); -}; - -jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { - mismatchKeys = mismatchKeys || []; - mismatchValues = mismatchValues || []; - - for (var i = 0; i < this.equalityTesters_.length; i++) { - var equalityTester = this.equalityTesters_[i]; - var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); - if (result !== jasmine.undefined) return result; - } - - if (a === b) return true; - - if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { - return (a == jasmine.undefined && b == jasmine.undefined); - } - - if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { - return a === b; - } - - if (a instanceof Date && b instanceof Date) { - return a.getTime() == b.getTime(); - } - - if (a instanceof jasmine.Matchers.Any) { - return a.matches(b); - } - - if (b instanceof jasmine.Matchers.Any) { - return b.matches(a); - } - - if (jasmine.isString_(a) && jasmine.isString_(b)) { - return (a == b); - } - - if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { - return (a == b); - } - - if (typeof a === "object" && typeof b === "object") { - return this.compareObjects_(a, b, mismatchKeys, mismatchValues); - } - - //Straight check - return (a === b); -}; - -jasmine.Env.prototype.contains_ = function(haystack, needle) { - if (jasmine.isArray_(haystack)) { - for (var i = 0; i < haystack.length; i++) { - if (this.equals_(haystack[i], needle)) return true; - } - return false; - } - return haystack.indexOf(needle) >= 0; -}; - -jasmine.Env.prototype.addEqualityTester = function(equalityTester) { - this.equalityTesters_.push(equalityTester); -}; -/** No-op base class for Jasmine reporters. - * - * @constructor - */ -jasmine.Reporter = function() { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerResults = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecStarting = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecResults = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.log = function(str) { -}; - -/** - * Blocks are functions with executable code that make up a spec. - * - * @constructor - * @param {jasmine.Env} env - * @param {Function} func - * @param {jasmine.Spec} spec - */ -jasmine.Block = function(env, func, spec) { - this.env = env; - this.func = func; - this.spec = spec; -}; - -jasmine.Block.prototype.execute = function(onComplete) { - try { - this.func.apply(this.spec); - } catch (e) { - this.spec.fail(e); - } - onComplete(); -}; -/** JavaScript API reporter. - * - * @constructor - */ -jasmine.JsApiReporter = function() { - this.started = false; - this.finished = false; - this.suites_ = []; - this.results_ = {}; -}; - -jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { - this.started = true; - var suites = runner.topLevelSuites(); - for (var i = 0; i < suites.length; i++) { - var suite = suites[i]; - this.suites_.push(this.summarize_(suite)); - } -}; - -jasmine.JsApiReporter.prototype.suites = function() { - return this.suites_; -}; - -jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { - var isSuite = suiteOrSpec instanceof jasmine.Suite; - var summary = { - id: suiteOrSpec.id, - name: suiteOrSpec.description, - type: isSuite ? 'suite' : 'spec', - children: [] - }; - - if (isSuite) { - var children = suiteOrSpec.children(); - for (var i = 0; i < children.length; i++) { - summary.children.push(this.summarize_(children[i])); - } - } - return summary; -}; - -jasmine.JsApiReporter.prototype.results = function() { - return this.results_; -}; - -jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { - return this.results_[specId]; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { - this.finished = true; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { - this.results_[spec.id] = { - messages: spec.results().getItems(), - result: spec.results().failedCount > 0 ? "failed" : "passed" - }; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.log = function(str) { -}; - -jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ - var results = {}; - for (var i = 0; i < specIds.length; i++) { - var specId = specIds[i]; - results[specId] = this.summarizeResult_(this.results_[specId]); - } - return results; -}; - -jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ - var summaryMessages = []; - var messagesLength = result.messages.length; - for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { - var resultMessage = result.messages[messageIndex]; - summaryMessages.push({ - text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, - passed: resultMessage.passed ? resultMessage.passed() : true, - type: resultMessage.type, - message: resultMessage.message, - trace: { - stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined - } - }); - } - - return { - result : result.result, - messages : summaryMessages - }; -}; - -/** - * @constructor - * @param {jasmine.Env} env - * @param actual - * @param {jasmine.Spec} spec - */ -jasmine.Matchers = function(env, actual, spec, opt_isNot) { - this.env = env; - this.actual = actual; - this.spec = spec; - this.isNot = opt_isNot || false; - this.reportWasCalled_ = false; -}; - -// todo: @deprecated as of Jasmine 0.11, remove soon [xw] -jasmine.Matchers.pp = function(str) { - throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); -}; - -// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] -jasmine.Matchers.prototype.report = function(result, failing_message, details) { - throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); -}; - -jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { - for (var methodName in prototype) { - if (methodName == 'report') continue; - var orig = prototype[methodName]; - matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); - } -}; - -jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { - return function() { - var matcherArgs = jasmine.util.argsToArray(arguments); - var result = matcherFunction.apply(this, arguments); - - if (this.isNot) { - result = !result; - } - - if (this.reportWasCalled_) return result; - - var message; - if (!result) { - if (this.message) { - message = this.message.apply(this, arguments); - if (jasmine.isArray_(message)) { - message = message[this.isNot ? 1 : 0]; - } - } else { - var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); - message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate; - if (matcherArgs.length > 0) { - for (var i = 0; i < matcherArgs.length; i++) { - if (i > 0) message += ","; - message += " " + jasmine.pp(matcherArgs[i]); - } - } - message += "."; - } - } - var expectationResult = new jasmine.ExpectationResult({ - matcherName: matcherName, - passed: result, - expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], - actual: this.actual, - message: message - }); - this.spec.addMatcherResult(expectationResult); - return jasmine.undefined; - }; -}; - - - - -/** - * toBe: compares the actual to the expected using === - * @param expected - */ -jasmine.Matchers.prototype.toBe = function(expected) { - return this.actual === expected; -}; - -/** - * toNotBe: compares the actual to the expected using !== - * @param expected - * @deprecated as of 1.0. Use not.toBe() instead. - */ -jasmine.Matchers.prototype.toNotBe = function(expected) { - return this.actual !== expected; -}; - -/** - * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. - * - * @param expected - */ -jasmine.Matchers.prototype.toEqual = function(expected) { - return this.env.equals_(this.actual, expected); -}; - -/** - * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual - * @param expected - * @deprecated as of 1.0. Use not.toNotEqual() instead. - */ -jasmine.Matchers.prototype.toNotEqual = function(expected) { - return !this.env.equals_(this.actual, expected); -}; - -/** - * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes - * a pattern or a String. - * - * @param expected - */ -jasmine.Matchers.prototype.toMatch = function(expected) { - return new RegExp(expected).test(this.actual); -}; - -/** - * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch - * @param expected - * @deprecated as of 1.0. Use not.toMatch() instead. - */ -jasmine.Matchers.prototype.toNotMatch = function(expected) { - return !(new RegExp(expected).test(this.actual)); -}; - -/** - * Matcher that compares the actual to jasmine.undefined. - */ -jasmine.Matchers.prototype.toBeDefined = function() { - return (this.actual !== jasmine.undefined); -}; - -/** - * Matcher that compares the actual to jasmine.undefined. - */ -jasmine.Matchers.prototype.toBeUndefined = function() { - return (this.actual === jasmine.undefined); -}; - -/** - * Matcher that compares the actual to null. - */ -jasmine.Matchers.prototype.toBeNull = function() { - return (this.actual === null); -}; - -/** - * Matcher that boolean not-nots the actual. - */ -jasmine.Matchers.prototype.toBeTruthy = function() { - return !!this.actual; -}; - - -/** - * Matcher that boolean nots the actual. - */ -jasmine.Matchers.prototype.toBeFalsy = function() { - return !this.actual; -}; - - -/** - * Matcher that checks to see if the actual, a Jasmine spy, was called. - */ -jasmine.Matchers.prototype.toHaveBeenCalled = function() { - if (arguments.length > 0) { - throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); - } - - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - - this.message = function() { - return [ - "Expected spy " + this.actual.identity + " to have been called.", - "Expected spy " + this.actual.identity + " not to have been called." - ]; - }; - - return this.actual.wasCalled; -}; - -/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */ -jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled; - -/** - * Matcher that checks to see if the actual, a Jasmine spy, was not called. - * - * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead - */ -jasmine.Matchers.prototype.wasNotCalled = function() { - if (arguments.length > 0) { - throw new Error('wasNotCalled does not take arguments'); - } - - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - - this.message = function() { - return [ - "Expected spy " + this.actual.identity + " to not have been called.", - "Expected spy " + this.actual.identity + " to have been called." - ]; - }; - - return !this.actual.wasCalled; -}; - -/** - * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. - * - * @example - * - */ -jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { - var expectedArgs = jasmine.util.argsToArray(arguments); - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - this.message = function() { - if (this.actual.callCount === 0) { - // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw] - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.", - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was." - ]; - } else { - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall), - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall) - ]; - } - }; - - return this.env.contains_(this.actual.argsForCall, expectedArgs); -}; - -/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */ -jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith; - -/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */ -jasmine.Matchers.prototype.wasNotCalledWith = function() { - var expectedArgs = jasmine.util.argsToArray(arguments); - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - - this.message = function() { - return [ - "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was", - "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was" - ]; - }; - - return !this.env.contains_(this.actual.argsForCall, expectedArgs); -}; - -/** - * Matcher that checks that the expected item is an element in the actual Array. - * - * @param {Object} expected - */ -jasmine.Matchers.prototype.toContain = function(expected) { - return this.env.contains_(this.actual, expected); -}; - -/** - * Matcher that checks that the expected item is NOT an element in the actual Array. - * - * @param {Object} expected - * @deprecated as of 1.0. Use not.toNotContain() instead. - */ -jasmine.Matchers.prototype.toNotContain = function(expected) { - return !this.env.contains_(this.actual, expected); -}; - -jasmine.Matchers.prototype.toBeLessThan = function(expected) { - return this.actual < expected; -}; - -jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { - return this.actual > expected; -}; - -/** - * Matcher that checks that the expected item is equal to the actual item - * up to a given level of decimal precision (default 2). - * - * @param {Number} expected - * @param {Number} precision - */ -jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { - if (!(precision === 0)) { - precision = precision || 2; - } - var multiplier = Math.pow(10, precision); - var actual = Math.round(this.actual * multiplier); - expected = Math.round(expected * multiplier); - return expected == actual; -}; - -/** - * Matcher that checks that the expected exception was thrown by the actual. - * - * @param {String} expected - */ -jasmine.Matchers.prototype.toThrow = function(expected) { - var result = false; - var exception; - if (typeof this.actual != 'function') { - throw new Error('Actual is not a function'); - } - try { - this.actual(); - } catch (e) { - exception = e; - } - if (exception) { - result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); - } - - var not = this.isNot ? "not " : ""; - - this.message = function() { - if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { - return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' '); - } else { - return "Expected function to throw an exception."; - } - }; - - return result; -}; - -jasmine.Matchers.Any = function(expectedClass) { - this.expectedClass = expectedClass; -}; - -jasmine.Matchers.Any.prototype.matches = function(other) { - if (this.expectedClass == String) { - return typeof other == 'string' || other instanceof String; - } - - if (this.expectedClass == Number) { - return typeof other == 'number' || other instanceof Number; - } - - if (this.expectedClass == Function) { - return typeof other == 'function' || other instanceof Function; - } - - if (this.expectedClass == Object) { - return typeof other == 'object'; - } - - return other instanceof this.expectedClass; -}; - -jasmine.Matchers.Any.prototype.toString = function() { - return ''; -}; - -/** - * @constructor - */ -jasmine.MultiReporter = function() { - this.subReporters_ = []; -}; -jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); - -jasmine.MultiReporter.prototype.addReporter = function(reporter) { - this.subReporters_.push(reporter); -}; - -(function() { - var functionNames = [ - "reportRunnerStarting", - "reportRunnerResults", - "reportSuiteResults", - "reportSpecStarting", - "reportSpecResults", - "log" - ]; - for (var i = 0; i < functionNames.length; i++) { - var functionName = functionNames[i]; - jasmine.MultiReporter.prototype[functionName] = (function(functionName) { - return function() { - for (var j = 0; j < this.subReporters_.length; j++) { - var subReporter = this.subReporters_[j]; - if (subReporter[functionName]) { - subReporter[functionName].apply(subReporter, arguments); - } - } - }; - })(functionName); - } -})(); -/** - * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults - * - * @constructor - */ -jasmine.NestedResults = function() { - /** - * The total count of results - */ - this.totalCount = 0; - /** - * Number of passed results - */ - this.passedCount = 0; - /** - * Number of failed results - */ - this.failedCount = 0; - /** - * Was this suite/spec skipped? - */ - this.skipped = false; - /** - * @ignore - */ - this.items_ = []; -}; - -/** - * Roll up the result counts. - * - * @param result - */ -jasmine.NestedResults.prototype.rollupCounts = function(result) { - this.totalCount += result.totalCount; - this.passedCount += result.passedCount; - this.failedCount += result.failedCount; -}; - -/** - * Adds a log message. - * @param values Array of message parts which will be concatenated later. - */ -jasmine.NestedResults.prototype.log = function(values) { - this.items_.push(new jasmine.MessageResult(values)); -}; - -/** - * Getter for the results: message & results. - */ -jasmine.NestedResults.prototype.getItems = function() { - return this.items_; -}; - -/** - * Adds a result, tracking counts (total, passed, & failed) - * @param {jasmine.ExpectationResult|jasmine.NestedResults} result - */ -jasmine.NestedResults.prototype.addResult = function(result) { - if (result.type != 'log') { - if (result.items_) { - this.rollupCounts(result); - } else { - this.totalCount++; - if (result.passed()) { - this.passedCount++; - } else { - this.failedCount++; - } - } - } - this.items_.push(result); -}; - -/** - * @returns {Boolean} True if everything below passed - */ -jasmine.NestedResults.prototype.passed = function() { - return this.passedCount === this.totalCount; -}; -/** - * Base class for pretty printing for expectation results. - */ -jasmine.PrettyPrinter = function() { - this.ppNestLevel_ = 0; -}; - -/** - * Formats a value in a nice, human-readable string. - * - * @param value - */ -jasmine.PrettyPrinter.prototype.format = function(value) { - if (this.ppNestLevel_ > 40) { - throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); - } - - this.ppNestLevel_++; - try { - if (value === jasmine.undefined) { - this.emitScalar('undefined'); - } else if (value === null) { - this.emitScalar('null'); - } else if (value === jasmine.getGlobal()) { - this.emitScalar(''); - } else if (value instanceof jasmine.Matchers.Any) { - this.emitScalar(value.toString()); - } else if (typeof value === 'string') { - this.emitString(value); - } else if (jasmine.isSpy(value)) { - this.emitScalar("spy on " + value.identity); - } else if (value instanceof RegExp) { - this.emitScalar(value.toString()); - } else if (typeof value === 'function') { - this.emitScalar('Function'); - } else if (typeof value.nodeType === 'number') { - this.emitScalar('HTMLNode'); - } else if (value instanceof Date) { - this.emitScalar('Date(' + value + ')'); - } else if (value.__Jasmine_been_here_before__) { - this.emitScalar(''); - } else if (jasmine.isArray_(value) || typeof value == 'object') { - value.__Jasmine_been_here_before__ = true; - if (jasmine.isArray_(value)) { - this.emitArray(value); - } else { - this.emitObject(value); - } - delete value.__Jasmine_been_here_before__; - } else { - this.emitScalar(value.toString()); - } - } finally { - this.ppNestLevel_--; - } -}; - -jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { - for (var property in obj) { - if (property == '__Jasmine_been_here_before__') continue; - fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && - obj.__lookupGetter__(property) !== null) : false); - } -}; - -jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; - -jasmine.StringPrettyPrinter = function() { - jasmine.PrettyPrinter.call(this); - - this.string = ''; -}; -jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); - -jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { - this.append(value); -}; - -jasmine.StringPrettyPrinter.prototype.emitString = function(value) { - this.append("'" + value + "'"); -}; - -jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { - this.append('[ '); - for (var i = 0; i < array.length; i++) { - if (i > 0) { - this.append(', '); - } - this.format(array[i]); - } - this.append(' ]'); -}; - -jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { - var self = this; - this.append('{ '); - var first = true; - - this.iterateObject(obj, function(property, isGetter) { - if (first) { - first = false; - } else { - self.append(', '); - } - - self.append(property); - self.append(' : '); - if (isGetter) { - self.append(''); - } else { - self.format(obj[property]); - } - }); - - this.append(' }'); -}; - -jasmine.StringPrettyPrinter.prototype.append = function(value) { - this.string += value; -}; -jasmine.Queue = function(env) { - this.env = env; - this.blocks = []; - this.running = false; - this.index = 0; - this.offset = 0; - this.abort = false; -}; - -jasmine.Queue.prototype.addBefore = function(block) { - this.blocks.unshift(block); -}; - -jasmine.Queue.prototype.add = function(block) { - this.blocks.push(block); -}; - -jasmine.Queue.prototype.insertNext = function(block) { - this.blocks.splice((this.index + this.offset + 1), 0, block); - this.offset++; -}; - -jasmine.Queue.prototype.start = function(onComplete) { - this.running = true; - this.onComplete = onComplete; - this.next_(); -}; - -jasmine.Queue.prototype.isRunning = function() { - return this.running; -}; - -jasmine.Queue.LOOP_DONT_RECURSE = true; - -jasmine.Queue.prototype.next_ = function() { - var self = this; - var goAgain = true; - - while (goAgain) { - goAgain = false; - - if (self.index < self.blocks.length && !this.abort) { - var calledSynchronously = true; - var completedSynchronously = false; - - var onComplete = function () { - if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { - completedSynchronously = true; - return; - } - - if (self.blocks[self.index].abort) { - self.abort = true; - } - - self.offset = 0; - self.index++; - - var now = new Date().getTime(); - if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { - self.env.lastUpdate = now; - self.env.setTimeout(function() { - self.next_(); - }, 0); - } else { - if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { - goAgain = true; - } else { - self.next_(); - } - } - }; - self.blocks[self.index].execute(onComplete); - - calledSynchronously = false; - if (completedSynchronously) { - onComplete(); - } - - } else { - self.running = false; - if (self.onComplete) { - self.onComplete(); - } - } - } -}; - -jasmine.Queue.prototype.results = function() { - var results = new jasmine.NestedResults(); - for (var i = 0; i < this.blocks.length; i++) { - if (this.blocks[i].results) { - results.addResult(this.blocks[i].results()); - } - } - return results; -}; - - -/** - * Runner - * - * @constructor - * @param {jasmine.Env} env - */ -jasmine.Runner = function(env) { - var self = this; - self.env = env; - self.queue = new jasmine.Queue(env); - self.before_ = []; - self.after_ = []; - self.suites_ = []; -}; - -jasmine.Runner.prototype.execute = function() { - var self = this; - if (self.env.reporter.reportRunnerStarting) { - self.env.reporter.reportRunnerStarting(this); - } - self.queue.start(function () { - self.finishCallback(); - }); -}; - -jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.splice(0,0,beforeEachFunction); -}; - -jasmine.Runner.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.splice(0,0,afterEachFunction); -}; - - -jasmine.Runner.prototype.finishCallback = function() { - this.env.reporter.reportRunnerResults(this); -}; - -jasmine.Runner.prototype.addSuite = function(suite) { - this.suites_.push(suite); -}; - -jasmine.Runner.prototype.add = function(block) { - if (block instanceof jasmine.Suite) { - this.addSuite(block); - } - this.queue.add(block); -}; - -jasmine.Runner.prototype.specs = function () { - var suites = this.suites(); - var specs = []; - for (var i = 0; i < suites.length; i++) { - specs = specs.concat(suites[i].specs()); - } - return specs; -}; - -jasmine.Runner.prototype.suites = function() { - return this.suites_; -}; - -jasmine.Runner.prototype.topLevelSuites = function() { - var topLevelSuites = []; - for (var i = 0; i < this.suites_.length; i++) { - if (!this.suites_[i].parentSuite) { - topLevelSuites.push(this.suites_[i]); - } - } - return topLevelSuites; -}; - -jasmine.Runner.prototype.results = function() { - return this.queue.results(); -}; -/** - * Internal representation of a Jasmine specification, or test. - * - * @constructor - * @param {jasmine.Env} env - * @param {jasmine.Suite} suite - * @param {String} description - */ -jasmine.Spec = function(env, suite, description) { - if (!env) { - throw new Error('jasmine.Env() required'); - } - if (!suite) { - throw new Error('jasmine.Suite() required'); - } - var spec = this; - spec.id = env.nextSpecId ? env.nextSpecId() : null; - spec.env = env; - spec.suite = suite; - spec.description = description; - spec.queue = new jasmine.Queue(env); - - spec.afterCallbacks = []; - spec.spies_ = []; - - spec.results_ = new jasmine.NestedResults(); - spec.results_.description = description; - spec.matchersClass = null; -}; - -jasmine.Spec.prototype.getFullName = function() { - return this.suite.getFullName() + ' ' + this.description + '.'; -}; - - -jasmine.Spec.prototype.results = function() { - return this.results_; -}; - -/** - * All parameters are pretty-printed and concatenated together, then written to the spec's output. - * - * Be careful not to leave calls to jasmine.log in production code. - */ -jasmine.Spec.prototype.log = function() { - return this.results_.log(arguments); -}; - -jasmine.Spec.prototype.runs = function (func) { - var block = new jasmine.Block(this.env, func, this); - this.addToQueue(block); - return this; -}; - -jasmine.Spec.prototype.addToQueue = function (block) { - if (this.queue.isRunning()) { - this.queue.insertNext(block); - } else { - this.queue.add(block); - } -}; - -/** - * @param {jasmine.ExpectationResult} result - */ -jasmine.Spec.prototype.addMatcherResult = function(result) { - this.results_.addResult(result); -}; - -jasmine.Spec.prototype.expect = function(actual) { - var positive = new (this.getMatchersClass_())(this.env, actual, this); - positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); - return positive; -}; - -/** - * Waits a fixed time period before moving to the next block. - * - * @deprecated Use waitsFor() instead - * @param {Number} timeout milliseconds to wait - */ -jasmine.Spec.prototype.waits = function(timeout) { - var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); - this.addToQueue(waitsFunc); - return this; -}; - -/** - * Waits for the latchFunction to return true before proceeding to the next block. - * - * @param {Function} latchFunction - * @param {String} optional_timeoutMessage - * @param {Number} optional_timeout - */ -jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { - var latchFunction_ = null; - var optional_timeoutMessage_ = null; - var optional_timeout_ = null; - - for (var i = 0; i < arguments.length; i++) { - var arg = arguments[i]; - switch (typeof arg) { - case 'function': - latchFunction_ = arg; - break; - case 'string': - optional_timeoutMessage_ = arg; - break; - case 'number': - optional_timeout_ = arg; - break; - } - } - - var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this); - this.addToQueue(waitsForFunc); - return this; -}; - -jasmine.Spec.prototype.fail = function (e) { - var expectationResult = new jasmine.ExpectationResult({ - passed: false, - message: e ? jasmine.util.formatException(e) : 'Exception', - trace: { stack: e.stack } - }); - this.results_.addResult(expectationResult); -}; - -jasmine.Spec.prototype.getMatchersClass_ = function() { - return this.matchersClass || this.env.matchersClass; -}; - -jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { - var parent = this.getMatchersClass_(); - var newMatchersClass = function() { - parent.apply(this, arguments); - }; - jasmine.util.inherit(newMatchersClass, parent); - jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); - this.matchersClass = newMatchersClass; -}; - -jasmine.Spec.prototype.finishCallback = function() { - this.env.reporter.reportSpecResults(this); -}; - -jasmine.Spec.prototype.finish = function(onComplete) { - this.removeAllSpies(); - this.finishCallback(); - if (onComplete) { - onComplete(); - } -}; - -jasmine.Spec.prototype.after = function(doAfter) { - if (this.queue.isRunning()) { - this.queue.add(new jasmine.Block(this.env, doAfter, this)); - } else { - this.afterCallbacks.unshift(doAfter); - } -}; - -jasmine.Spec.prototype.execute = function(onComplete) { - var spec = this; - if (!spec.env.specFilter(spec)) { - spec.results_.skipped = true; - spec.finish(onComplete); - return; - } - - this.env.reporter.reportSpecStarting(this); - - spec.env.currentSpec = spec; - - spec.addBeforesAndAftersToQueue(); - - spec.queue.start(function () { - spec.finish(onComplete); - }); -}; - -jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { - var runner = this.env.currentRunner(); - var i; - - for (var suite = this.suite; suite; suite = suite.parentSuite) { - for (i = 0; i < suite.before_.length; i++) { - this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); - } - } - for (i = 0; i < runner.before_.length; i++) { - this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); - } - for (i = 0; i < this.afterCallbacks.length; i++) { - this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); - } - for (suite = this.suite; suite; suite = suite.parentSuite) { - for (i = 0; i < suite.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); - } - } - for (i = 0; i < runner.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); - } -}; - -jasmine.Spec.prototype.explodes = function() { - throw 'explodes function should not have been called'; -}; - -jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { - if (obj == jasmine.undefined) { - throw "spyOn could not find an object to spy upon for " + methodName + "()"; - } - - if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { - throw methodName + '() method does not exist'; - } - - if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { - throw new Error(methodName + ' has already been spied upon'); - } - - var spyObj = jasmine.createSpy(methodName); - - this.spies_.push(spyObj); - spyObj.baseObj = obj; - spyObj.methodName = methodName; - spyObj.originalValue = obj[methodName]; - - obj[methodName] = spyObj; - - return spyObj; -}; - -jasmine.Spec.prototype.removeAllSpies = function() { - for (var i = 0; i < this.spies_.length; i++) { - var spy = this.spies_[i]; - spy.baseObj[spy.methodName] = spy.originalValue; - } - this.spies_ = []; -}; - -/** - * Internal representation of a Jasmine suite. - * - * @constructor - * @param {jasmine.Env} env - * @param {String} description - * @param {Function} specDefinitions - * @param {jasmine.Suite} parentSuite - */ -jasmine.Suite = function(env, description, specDefinitions, parentSuite) { - var self = this; - self.id = env.nextSuiteId ? env.nextSuiteId() : null; - self.description = description; - self.queue = new jasmine.Queue(env); - self.parentSuite = parentSuite; - self.env = env; - self.before_ = []; - self.after_ = []; - self.children_ = []; - self.suites_ = []; - self.specs_ = []; -}; - -jasmine.Suite.prototype.getFullName = function() { - var fullName = this.description; - for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { - fullName = parentSuite.description + ' ' + fullName; - } - return fullName; -}; - -jasmine.Suite.prototype.finish = function(onComplete) { - this.env.reporter.reportSuiteResults(this); - this.finished = true; - if (typeof(onComplete) == 'function') { - onComplete(); - } -}; - -jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.unshift(beforeEachFunction); -}; - -jasmine.Suite.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.unshift(afterEachFunction); -}; - -jasmine.Suite.prototype.results = function() { - return this.queue.results(); -}; - -jasmine.Suite.prototype.add = function(suiteOrSpec) { - this.children_.push(suiteOrSpec); - if (suiteOrSpec instanceof jasmine.Suite) { - this.suites_.push(suiteOrSpec); - this.env.currentRunner().addSuite(suiteOrSpec); - } else { - this.specs_.push(suiteOrSpec); - } - this.queue.add(suiteOrSpec); -}; - -jasmine.Suite.prototype.specs = function() { - return this.specs_; -}; - -jasmine.Suite.prototype.suites = function() { - return this.suites_; -}; - -jasmine.Suite.prototype.children = function() { - return this.children_; -}; - -jasmine.Suite.prototype.execute = function(onComplete) { - var self = this; - this.queue.start(function () { - self.finish(onComplete); - }); -}; -jasmine.WaitsBlock = function(env, timeout, spec) { - this.timeout = timeout; - jasmine.Block.call(this, env, null, spec); -}; - -jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); - -jasmine.WaitsBlock.prototype.execute = function (onComplete) { - if (jasmine.VERBOSE) { - this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); - } - this.env.setTimeout(function () { - onComplete(); - }, this.timeout); -}; -/** - * A block which waits for some condition to become true, with timeout. - * - * @constructor - * @extends jasmine.Block - * @param {jasmine.Env} env The Jasmine environment. - * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true. - * @param {Function} latchFunction A function which returns true when the desired condition has been met. - * @param {String} message The message to display if the desired condition hasn't been met within the given time period. - * @param {jasmine.Spec} spec The Jasmine spec. - */ -jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { - this.timeout = timeout || env.defaultTimeoutInterval; - this.latchFunction = latchFunction; - this.message = message; - this.totalTimeSpentWaitingForLatch = 0; - jasmine.Block.call(this, env, null, spec); -}; -jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); - -jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10; - -jasmine.WaitsForBlock.prototype.execute = function(onComplete) { - if (jasmine.VERBOSE) { - this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen')); - } - var latchFunctionResult; - try { - latchFunctionResult = this.latchFunction.apply(this.spec); - } catch (e) { - this.spec.fail(e); - onComplete(); - return; - } - - if (latchFunctionResult) { - onComplete(); - } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) { - var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen'); - this.spec.fail({ - name: 'timeout', - message: message - }); - - this.abort = true; - onComplete(); - } else { - this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; - var self = this; - this.env.setTimeout(function() { - self.execute(onComplete); - }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); - } -}; -// Mock setTimeout, clearTimeout -// Contributed by Pivotal Computer Systems, www.pivotalsf.com - -jasmine.FakeTimer = function() { - this.reset(); - - var self = this; - self.setTimeout = function(funcToCall, millis) { - self.timeoutsMade++; - self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); - return self.timeoutsMade; - }; - - self.setInterval = function(funcToCall, millis) { - self.timeoutsMade++; - self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); - return self.timeoutsMade; - }; - - self.clearTimeout = function(timeoutKey) { - self.scheduledFunctions[timeoutKey] = jasmine.undefined; - }; - - self.clearInterval = function(timeoutKey) { - self.scheduledFunctions[timeoutKey] = jasmine.undefined; - }; - -}; - -jasmine.FakeTimer.prototype.reset = function() { - this.timeoutsMade = 0; - this.scheduledFunctions = {}; - this.nowMillis = 0; -}; - -jasmine.FakeTimer.prototype.tick = function(millis) { - var oldMillis = this.nowMillis; - var newMillis = oldMillis + millis; - this.runFunctionsWithinRange(oldMillis, newMillis); - this.nowMillis = newMillis; -}; - -jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { - var scheduledFunc; - var funcsToRun = []; - for (var timeoutKey in this.scheduledFunctions) { - scheduledFunc = this.scheduledFunctions[timeoutKey]; - if (scheduledFunc != jasmine.undefined && - scheduledFunc.runAtMillis >= oldMillis && - scheduledFunc.runAtMillis <= nowMillis) { - funcsToRun.push(scheduledFunc); - this.scheduledFunctions[timeoutKey] = jasmine.undefined; - } - } - - if (funcsToRun.length > 0) { - funcsToRun.sort(function(a, b) { - return a.runAtMillis - b.runAtMillis; - }); - for (var i = 0; i < funcsToRun.length; ++i) { - try { - var funcToRun = funcsToRun[i]; - this.nowMillis = funcToRun.runAtMillis; - funcToRun.funcToCall(); - if (funcToRun.recurring) { - this.scheduleFunction(funcToRun.timeoutKey, - funcToRun.funcToCall, - funcToRun.millis, - true); - } - } catch(e) { - } - } - this.runFunctionsWithinRange(oldMillis, nowMillis); - } -}; - -jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { - this.scheduledFunctions[timeoutKey] = { - runAtMillis: this.nowMillis + millis, - funcToCall: funcToCall, - recurring: recurring, - timeoutKey: timeoutKey, - millis: millis - }; -}; - -/** - * @namespace - */ -jasmine.Clock = { - defaultFakeTimer: new jasmine.FakeTimer(), - - reset: function() { - jasmine.Clock.assertInstalled(); - jasmine.Clock.defaultFakeTimer.reset(); - }, - - tick: function(millis) { - jasmine.Clock.assertInstalled(); - jasmine.Clock.defaultFakeTimer.tick(millis); - }, - - runFunctionsWithinRange: function(oldMillis, nowMillis) { - jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); - }, - - scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { - jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); - }, - - useMock: function() { - if (!jasmine.Clock.isInstalled()) { - var spec = jasmine.getEnv().currentSpec; - spec.after(jasmine.Clock.uninstallMock); - - jasmine.Clock.installMock(); - } - }, - - installMock: function() { - jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; - }, - - uninstallMock: function() { - jasmine.Clock.assertInstalled(); - jasmine.Clock.installed = jasmine.Clock.real; - }, - - real: { - setTimeout: jasmine.getGlobal().setTimeout, - clearTimeout: jasmine.getGlobal().clearTimeout, - setInterval: jasmine.getGlobal().setInterval, - clearInterval: jasmine.getGlobal().clearInterval - }, - - assertInstalled: function() { - if (!jasmine.Clock.isInstalled()) { - throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); - } - }, - - isInstalled: function() { - return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; - }, - - installed: null -}; -jasmine.Clock.installed = jasmine.Clock.real; - -//else for IE support -jasmine.getGlobal().setTimeout = function(funcToCall, millis) { - if (jasmine.Clock.installed.setTimeout.apply) { - return jasmine.Clock.installed.setTimeout.apply(this, arguments); - } else { - return jasmine.Clock.installed.setTimeout(funcToCall, millis); - } -}; - -jasmine.getGlobal().setInterval = function(funcToCall, millis) { - if (jasmine.Clock.installed.setInterval.apply) { - return jasmine.Clock.installed.setInterval.apply(this, arguments); - } else { - return jasmine.Clock.installed.setInterval(funcToCall, millis); - } -}; - -jasmine.getGlobal().clearTimeout = function(timeoutKey) { - if (jasmine.Clock.installed.clearTimeout.apply) { - return jasmine.Clock.installed.clearTimeout.apply(this, arguments); - } else { - return jasmine.Clock.installed.clearTimeout(timeoutKey); - } -}; - -jasmine.getGlobal().clearInterval = function(timeoutKey) { - if (jasmine.Clock.installed.clearTimeout.apply) { - return jasmine.Clock.installed.clearInterval.apply(this, arguments); - } else { - return jasmine.Clock.installed.clearInterval(timeoutKey); - } -}; - -jasmine.version_= { - "major": 1, - "minor": 1, - "build": 0, - "revision": 1315677058 -}; diff --git a/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine_favicon.png b/addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine_favicon.png deleted file mode 100644 index bd1479552544d199a5556d83dc2569f11bf2851d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 700 zcmV;t0z>_YP)x|DS(-`hVk&m6uaeBHAzBIr9m`fBO0H{}I}dDlaR1Gn{|`Rg{=ezgwExSlw*0^H>eT;B zw@?2+e0ulCc}u44OGpea6B6VTN6{=MDkK{n9ayyMz=p>l#n)e6_`mJ$?Em$Lz5egG zH~;^$&k$F=`2PI=qxbjzmy~5sWCDc+4-c16NT^Q^FwibOczfp`EWkh-F1|YUf60}` z|CfL?hz|=NP+)G~zu~61n6LtajkR&`ffL(bzWVX}|1*$gXe@xD?9Qtj{~v#T@c+S^ zyZ)U_N-Z=4Y z+upS=Za%pJHW1|Wy+^jZNK6c?$t_6jYHX>P+1yq++u6w~93BS3Lj2-(cIJK_9u5&2 z>Pn_SZxw^173gG;i;iDB_)=0*Or3#PU}~!GdhOB0@8E<5^z)H(`(8*%ifIsSfVh~D z{O-eB?!Nr-;{TIR5C1o{RxAMJ3!)8RW@ch-@2+2d_WJR+MI{+Mq9TG)45R`RV_hdt iPlrTCMg}GZS^)r2gqD6|@^jb#0000 -1, - WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, - Gecko: navigator.userAgent.indexOf('Gecko') > -1 && - navigator.userAgent.indexOf('KHTML') === -1, - MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) - }, - - BrowserFeatures: { - XPath: !!document.evaluate, - SelectorsAPI: !!document.querySelector, - ElementExtensions: !!window.HTMLElement, - SpecificElementExtensions: - document.createElement('div')['__proto__'] && - document.createElement('div')['__proto__'] !== - document.createElement('form')['__proto__'] - }, - - ScriptFragment: ']*>([\\S\\s]*?)<\/script>', - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, - - emptyFunction: function() { }, - K: function(x) { return x } -}; - -if (Prototype.Browser.MobileSafari) - Prototype.BrowserFeatures.SpecificElementExtensions = false; - - -/* Based on Alex Arnell's inheritance implementation. */ -var Class = { - create: function() { - var parent = null, properties = $A(arguments); - if (Object.isFunction(properties[0])) - parent = properties.shift(); - - function klass() { - this.initialize.apply(this, arguments); - } - - Object.extend(klass, Class.Methods); - klass.superclass = parent; - klass.subclasses = []; - - if (parent) { - var subclass = function() { }; - subclass.prototype = parent.prototype; - klass.prototype = new subclass; - parent.subclasses.push(klass); - } - - for (var i = 0; i < properties.length; i++) - klass.addMethods(properties[i]); - - if (!klass.prototype.initialize) - klass.prototype.initialize = Prototype.emptyFunction; - - klass.prototype.constructor = klass; - - return klass; - } -}; - -Class.Methods = { - addMethods: function(source) { - var ancestor = this.superclass && this.superclass.prototype; - var properties = Object.keys(source); - - if (!Object.keys({ toString: true }).length) - properties.push("toString", "valueOf"); - - for (var i = 0, length = properties.length; i < length; i++) { - var property = properties[i], value = source[property]; - if (ancestor && Object.isFunction(value) && - value.argumentNames().first() == "$super") { - var method = value; - value = (function(m) { - return function() { return ancestor[m].apply(this, arguments) }; - })(property).wrap(method); - - value.valueOf = method.valueOf.bind(method); - value.toString = method.toString.bind(method); - } - this.prototype[property] = value; - } - - return this; - } -}; - -var Abstract = { }; - -Object.extend = function(destination, source) { - for (var property in source) - destination[property] = source[property]; - return destination; -}; - -Object.extend(Object, { - inspect: function(object) { - try { - if (Object.isUndefined(object)) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : String(object); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - }, - - toJSON: function(object) { - var type = typeof object; - switch (type) { - case 'undefined': - case 'function': - case 'unknown': return; - case 'boolean': return object.toString(); - } - - if (object === null) return 'null'; - if (object.toJSON) return object.toJSON(); - if (Object.isElement(object)) return; - - var results = []; - for (var property in object) { - var value = Object.toJSON(object[property]); - if (!Object.isUndefined(value)) - results.push(property.toJSON() + ': ' + value); - } - - return '{' + results.join(', ') + '}'; - }, - - toQueryString: function(object) { - return $H(object).toQueryString(); - }, - - toHTML: function(object) { - return object && object.toHTML ? object.toHTML() : String.interpret(object); - }, - - keys: function(object) { - var keys = []; - for (var property in object) - keys.push(property); - return keys; - }, - - values: function(object) { - var values = []; - for (var property in object) - values.push(object[property]); - return values; - }, - - clone: function(object) { - return Object.extend({ }, object); - }, - - isElement: function(object) { - return !!(object && object.nodeType == 1); - }, - - isArray: function(object) { - return object != null && typeof object == "object" && - 'splice' in object && 'join' in object; - }, - - isHash: function(object) { - return object instanceof Hash; - }, - - isFunction: function(object) { - return typeof object == "function"; - }, - - isString: function(object) { - return typeof object == "string"; - }, - - isNumber: function(object) { - return typeof object == "number"; - }, - - isUndefined: function(object) { - return typeof object == "undefined"; - } -}); - -Object.extend(Function.prototype, { - argumentNames: function() { - var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1] - .replace(/\s+/g, '').split(','); - return names.length == 1 && !names[0] ? [] : names; - }, - - bind: function() { - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } - }, - - bindAsEventListener: function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [event || window.event].concat(args)); - } - }, - - curry: function() { - if (!arguments.length) return this; - var __method = this, args = $A(arguments); - return function() { - return __method.apply(this, args.concat($A(arguments))); - } - }, - - delay: function() { - var __method = this, args = $A(arguments), timeout = args.shift() * 1000; - return window.setTimeout(function() { - return __method.apply(__method, args); - }, timeout); - }, - - defer: function() { - var args = [0.01].concat($A(arguments)); - return this.delay.apply(this, args); - }, - - wrap: function(wrapper) { - var __method = this; - return function() { - return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); - } - }, - - methodize: function() { - if (this._methodized) return this._methodized; - var __method = this; - return this._methodized = function() { - return __method.apply(null, [this].concat($A(arguments))); - }; - } -}); - -Date.prototype.toJSON = function() { - return '"' + this.getUTCFullYear() + '-' + - (this.getUTCMonth() + 1).toPaddedString(2) + '-' + - this.getUTCDate().toPaddedString(2) + 'T' + - this.getUTCHours().toPaddedString(2) + ':' + - this.getUTCMinutes().toPaddedString(2) + ':' + - this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) { } - } - - return returnValue; - } -}; - -RegExp.prototype.match = RegExp.prototype.test; - -RegExp.escape = function(str) { - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create({ - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - execute: function() { - this.callback(this); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.execute(); - } finally { - this.currentlyExecuting = false; - } - } - } -}); -Object.extend(String, { - interpret: function(value) { - return value == null ? '' : String(value); - }, - specialChar: { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '\\': '\\\\' - } -}); - -Object.extend(String.prototype, { - gsub: function(pattern, replacement) { - var result = '', source = this, match; - replacement = arguments.callee.prepareReplacement(replacement); - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - }, - - sub: function(pattern, replacement, count) { - replacement = this.gsub.prepareReplacement(replacement); - count = Object.isUndefined(count) ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - }, - - scan: function(pattern, iterator) { - this.gsub(pattern, iterator); - return String(this); - }, - - truncate: function(length, truncation) { - length = length || 30; - truncation = Object.isUndefined(truncation) ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : String(this); - }, - - strip: function() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - }, - - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(function(script) { return eval(script) }); - }, - - escapeHTML: function() { - var self = arguments.callee; - self.text.data = this; - return self.div.innerHTML; - }, - - unescapeHTML: function() { - var div = new Element('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? (div.childNodes.length > 1 ? - $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : - div.childNodes[0].nodeValue) : ''; - }, - - toQueryParams: function(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return { }; - - return match[1].split(separator || '&').inject({ }, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var key = decodeURIComponent(pair.shift()); - var value = pair.length > 1 ? pair.join('=') : pair[0]; - if (value != undefined) value = decodeURIComponent(value); - - if (key in hash) { - if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; - hash[key].push(value); - } - else hash[key] = value; - } - return hash; - }); - }, - - toArray: function() { - return this.split(''); - }, - - succ: function() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - }, - - times: function(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - }, - - camelize: function() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - }, - - capitalize: function() { - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - }, - - underscore: function() { - return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); - }, - - dasherize: function() { - return this.gsub(/_/,'-'); - }, - - inspect: function(useDoubleQuotes) { - var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { - var character = String.specialChar[match[0]]; - return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); - }); - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - }, - - toJSON: function() { - return this.inspect(true); - }, - - unfilterJSON: function(filter) { - return this.sub(filter || Prototype.JSONFilter, '#{1}'); - }, - - isJSON: function() { - var str = this; - if (str.blank()) return false; - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); - }, - - evalJSON: function(sanitize) { - var json = this.unfilterJSON(); - try { - if (!sanitize || json.isJSON()) return eval('(' + json + ')'); - } catch (e) { } - throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); - }, - - include: function(pattern) { - return this.indexOf(pattern) > -1; - }, - - startsWith: function(pattern) { - return this.indexOf(pattern) === 0; - }, - - endsWith: function(pattern) { - var d = this.length - pattern.length; - return d >= 0 && this.lastIndexOf(pattern) === d; - }, - - empty: function() { - return this == ''; - }, - - blank: function() { - return /^\s*$/.test(this); - }, - - interpolate: function(object, pattern) { - return new Template(this, pattern).evaluate(object); - } -}); - -if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { - escapeHTML: function() { - return this.replace(/&/g,'&').replace(//g,'>'); - }, - unescapeHTML: function() { - return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); - } -}); - -String.prototype.gsub.prepareReplacement = function(replacement) { - if (Object.isFunction(replacement)) return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; -}; - -String.prototype.parseQuery = String.prototype.toQueryParams; - -Object.extend(String.prototype.escapeHTML, { - div: document.createElement('div'), - text: document.createTextNode('') -}); - -String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); - -var Template = Class.create({ - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - if (Object.isFunction(object.toTemplateReplacements)) - object = object.toTemplateReplacements(); - - return this.template.gsub(this.pattern, function(match) { - if (object == null) return ''; - - var before = match[1] || ''; - if (before == '\\') return match[2]; - - var ctx = object, expr = match[3]; - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; - match = pattern.exec(expr); - if (match == null) return before; - - while (match != null) { - var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; - ctx = ctx[comp]; - if (null == ctx || '' == match[3]) break; - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); - match = pattern.exec(expr); - } - - return before + String.interpret(ctx); - }); - } -}); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; - -var $break = { }; - -var Enumerable = { - each: function(iterator, context) { - var index = 0; - try { - this._each(function(value) { - iterator.call(context, value, index++); - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - }, - - eachSlice: function(number, iterator, context) { - var index = -number, slices = [], array = this.toArray(); - if (number < 1) return array; - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.collect(iterator, context); - }, - - all: function(iterator, context) { - iterator = iterator || Prototype.K; - var result = true; - this.each(function(value, index) { - result = result && !!iterator.call(context, value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator, context) { - iterator = iterator || Prototype.K; - var result = false; - this.each(function(value, index) { - if (result = !!iterator.call(context, value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - this.each(function(value, index) { - results.push(iterator.call(context, value, index)); - }); - return results; - }, - - detect: function(iterator, context) { - var result; - this.each(function(value, index) { - if (iterator.call(context, value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator, context) { - var results = []; - this.each(function(value, index) { - if (iterator.call(context, value, index)) - results.push(value); - }); - return results; - }, - - grep: function(filter, iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - - if (Object.isString(filter)) - filter = new RegExp(filter); - - this.each(function(value, index) { - if (filter.match(value)) - results.push(iterator.call(context, value, index)); - }); - return results; - }, - - include: function(object) { - if (Object.isFunction(this.indexOf)) - if (this.indexOf(object) != -1) return true; - - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inGroupsOf: function(number, fillWith) { - fillWith = Object.isUndefined(fillWith) ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - }, - - inject: function(memo, iterator, context) { - this.each(function(value, index) { - memo = iterator.call(context, memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value >= result) - result = value; - }); - return result; - }, - - min: function(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value < result) - result = value; - }); - return result; - }, - - partition: function(iterator, context) { - iterator = iterator || Prototype.K; - var trues = [], falses = []; - this.each(function(value, index) { - (iterator.call(context, value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator, context) { - var results = []; - this.each(function(value, index) { - if (!iterator.call(context, value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator, context) { - return this.map(function(value, index) { - return { - value: value, - criteria: iterator.call(context, value, index) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.map(); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (Object.isFunction(args.last())) - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - }, - - size: function() { - return this.toArray().length; - }, - - inspect: function() { - return '#'; - } -}; - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - filter: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray, - every: Enumerable.all, - some: Enumerable.any -}); -function $A(iterable) { - if (!iterable) return []; - if (iterable.toArray) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; -} - -if (Prototype.Browser.WebKit) { - $A = function(iterable) { - if (!iterable) return []; - // In Safari, only use the `toArray` method if it's not a NodeList. - // A NodeList is a function, has an function `item` property, and a numeric - // `length` property. Adapted from Google Doctype. - if (!(typeof iterable === 'function' && typeof iterable.length === - 'number' && typeof iterable.item === 'function') && iterable.toArray) - return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; - }; -} - -Array.from = $A; - -Object.extend(Array.prototype, Enumerable); - -if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(Object.isArray(value) ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - reduce: function() { - return this.length > 1 ? this : this[0]; - }, - - uniq: function(sorted) { - return this.inject([], function(array, value, index) { - if (0 == index || (sorted ? array.last() != value : !array.include(value))) - array.push(value); - return array; - }); - }, - - intersect: function(array) { - return this.uniq().findAll(function(item) { - return array.detect(function(value) { return item === value }); - }); - }, - - clone: function() { - return [].concat(this); - }, - - size: function() { - return this.length; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - }, - - toJSON: function() { - var results = []; - this.each(function(object) { - var value = Object.toJSON(object); - if (!Object.isUndefined(value)) results.push(value); - }); - return '[' + results.join(', ') + ']'; - } -}); - -// use native browser JS 1.6 implementation if available -if (Object.isFunction(Array.prototype.forEach)) - Array.prototype._each = Array.prototype.forEach; - -if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { - i || (i = 0); - var length = this.length; - if (i < 0) i = length + i; - for (; i < length; i++) - if (this[i] === item) return i; - return -1; -}; - -if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; - var n = this.slice(0, i).reverse().indexOf(item); - return (n < 0) ? n : i - n - 1; -}; - -Array.prototype.toArray = Array.prototype.clone; - -function $w(string) { - if (!Object.isString(string)) return []; - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -if (Prototype.Browser.Opera){ - Array.prototype.concat = function() { - var array = []; - for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); - for (var i = 0, length = arguments.length; i < length; i++) { - if (Object.isArray(arguments[i])) { - for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) - array.push(arguments[i][j]); - } else { - array.push(arguments[i]); - } - } - return array; - }; -} -Object.extend(Number.prototype, { - toColorPart: function() { - return this.toPaddedString(2, 16); - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator, context) { - $R(0, this, true).each(iterator, context); - return this; - }, - - toPaddedString: function(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; - }, - - toJSON: function() { - return isFinite(this) ? this.toString() : 'null'; - } -}); - -$w('abs round ceil floor').each(function(method){ - Number.prototype[method] = Math[method].methodize(); -}); -function $H(object) { - return new Hash(object); -}; - -var Hash = Class.create(Enumerable, (function() { - - function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); - } - - return { - initialize: function(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - }, - - _each: function(iterator) { - for (var key in this._object) { - var value = this._object[key], pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - set: function(key, value) { - return this._object[key] = value; - }, - - get: function(key) { - // simulating poorly supported hasOwnProperty - if (this._object[key] !== Object.prototype[key]) - return this._object[key]; - }, - - unset: function(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - }, - - toObject: function() { - return Object.clone(this._object); - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - index: function(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - }, - - merge: function(object) { - return this.clone().update(object); - }, - - update: function(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - }, - - toQueryString: function() { - return this.inject([], function(results, pair) { - var key = encodeURIComponent(pair.key), values = pair.value; - - if (values && typeof values == 'object') { - if (Object.isArray(values)) - return results.concat(values.map(toQueryPair.curry(key))); - } else results.push(toQueryPair(key, values)); - return results; - }).join('&'); - }, - - inspect: function() { - return '#'; - }, - - toJSON: function() { - return Object.toJSON(this.toObject()); - }, - - clone: function() { - return new Hash(this); - } - } -})()); - -Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; -Hash.from = $H; -var ObjectRange = Class.create(Enumerable, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -}; - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (Object.isFunction(responder[callback])) { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) { } - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { Ajax.activeRequestCount++ }, - onComplete: function() { Ajax.activeRequestCount-- } -}); - -Ajax.Base = Class.create({ - initialize: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '', - evalJSON: true, - evalJS: true - }; - Object.extend(this.options, options || { }); - - this.options.method = this.options.method.toLowerCase(); - - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) - this.options.parameters = this.options.parameters.toObject(); - } -}); - -Ajax.Request = Class.create(Ajax.Base, { - _complete: false, - - initialize: function($super, url, options) { - $super(options); - this.transport = Ajax.getTransport(); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = Object.clone(this.options.parameters); - - if (!['get', 'post'].include(this.method)) { - // simulate other verbs over post - params['_method'] = this.method; - this.method = 'post'; - } - - this.parameters = params; - - if (params = Object.toQueryString(params)) { - // when GET, append parameters to URL - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; - } - - try { - var response = new Ajax.Response(this); - if (this.options.onCreate) this.options.onCreate(response); - Ajax.Responders.dispatch('onCreate', this, response); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - this.body = this.method == 'post' ? (this.options.postBody || params) : null; - this.transport.send(this.body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - // user-defined headers - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (Object.isFunction(extras.push)) - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - var status = this.getStatus(); - return !status || (status >= 200 && status < 300); - }, - - getStatus: function() { - try { - return this.transport.status || 0; - } catch (e) { return 0 } - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + response.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - var contentType = response.getHeader('Content-type'); - if (this.options.evalJS == 'force' - || (this.options.evalJS && this.isSameOrigin() && contentType - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - // avoid memory leak in MSIE: clean up - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - isSameOrigin: function() { - var m = this.url.match(/^\s*https?:\/\/[^\/]*/); - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ - protocol: location.protocol, - domain: document.domain, - port: location.port ? ':' + location.port : '' - })); - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name) || null; - } catch (e) { return null } - }, - - evalResponse: function() { - try { - return eval((this.transport.responseText || '').unfilterJSON()); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Response = Class.create({ - initialize: function(request){ - this.request = request; - var transport = this.transport = request.transport, - readyState = this.readyState = transport.readyState; - - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { - this.status = this.getStatus(); - this.statusText = this.getStatusText(); - this.responseText = String.interpret(transport.responseText); - this.headerJSON = this._getHeaderJSON(); - } - - if(readyState == 4) { - var xml = transport.responseXML; - this.responseXML = Object.isUndefined(xml) ? null : xml; - this.responseJSON = this._getResponseJSON(); - } - }, - - status: 0, - statusText: '', - - getStatus: Ajax.Request.prototype.getStatus, - - getStatusText: function() { - try { - return this.transport.statusText || ''; - } catch (e) { return '' } - }, - - getHeader: Ajax.Request.prototype.getHeader, - - getAllHeaders: function() { - try { - return this.getAllResponseHeaders(); - } catch (e) { return null } - }, - - getResponseHeader: function(name) { - return this.transport.getResponseHeader(name); - }, - - getAllResponseHeaders: function() { - return this.transport.getAllResponseHeaders(); - }, - - _getHeaderJSON: function() { - var json = this.getHeader('X-JSON'); - if (!json) return null; - json = decodeURIComponent(escape(json)); - try { - return json.evalJSON(this.request.options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - }, - - _getResponseJSON: function() { - var options = this.request.options; - if (!options.evalJSON || (options.evalJSON != 'force' && - !(this.getHeader('Content-type') || '').include('application/json')) || - this.responseText.blank()) - return null; - try { - return this.responseText.evalJSON(options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - } -}); - -Ajax.Updater = Class.create(Ajax.Request, { - initialize: function($super, container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - }; - - options = Object.clone(options); - var onComplete = options.onComplete; - options.onComplete = (function(response, json) { - this.updateContent(response.responseText); - if (Object.isFunction(onComplete)) onComplete(response, json); - }).bind(this); - - $super(url, options); - }, - - updateContent: function(responseText) { - var receiver = this.container[this.success() ? 'success' : 'failure'], - options = this.options; - - if (!options.evalScripts) responseText = responseText.stripScripts(); - - if (receiver = $(receiver)) { - if (options.insertion) { - if (Object.isString(options.insertion)) { - var insertion = { }; insertion[options.insertion] = responseText; - receiver.insert(insertion); - } - else options.insertion(receiver, responseText); - } - else receiver.update(responseText); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { - initialize: function($super, container, url, options) { - $super(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = { }; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(response) { - if (this.options.decay) { - this.decay = (response.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = response.responseText; - } - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (Object.isString(element)) - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(Element.extend(query.snapshotItem(i))); - return results; - }; -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Node) var Node = { }; - -if (!Node.ELEMENT_NODE) { - // DOM level 2 ECMAScript Language Binding - Object.extend(Node, { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }); -} - -(function() { - var element = this.Element; - this.Element = function(tagName, attributes) { - attributes = attributes || { }; - tagName = tagName.toLowerCase(); - var cache = Element.cache; - if (Prototype.Browser.IE && attributes.name) { - tagName = '<' + tagName + ' name="' + attributes.name + '">'; - delete attributes.name; - return Element.writeAttribute(document.createElement(tagName), attributes); - } - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); - }; - Object.extend(this.Element, element || { }); - if (element) this.Element.prototype = element.prototype; -}).call(window); - -Element.cache = { }; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - hide: function(element) { - element = $(element); - element.style.display = 'none'; - return element; - }, - - show: function(element) { - element = $(element); - element.style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - content = Object.toHTML(content); - element.innerHTML = content.stripScripts(); - content.evalScripts.bind(content).defer(); - return element; - }, - - replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); - range.selectNode(element); - content.evalScripts.bind(content).defer(); - content = range.createContextualFragment(content.stripScripts()); - } - element.parentNode.replaceChild(content, element); - return element; - }, - - insert: function(element, insertions) { - element = $(element); - - if (Object.isString(insertions) || Object.isNumber(insertions) || - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) - insertions = {bottom:insertions}; - - var content, insert, tagName, childNodes; - - for (var position in insertions) { - content = insertions[position]; - position = position.toLowerCase(); - insert = Element._insertionTranslations[position]; - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - insert(element, content); - continue; - } - - content = Object.toHTML(content); - - tagName = ((position == 'before' || position == 'after') - ? element.parentNode : element).tagName.toUpperCase(); - - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - - if (position == 'top' || position == 'after') childNodes.reverse(); - childNodes.each(insert.curry(element)); - - content.evalScripts.bind(content).defer(); - } - - return element; - }, - - wrap: function(element, wrapper, attributes) { - element = $(element); - if (Object.isElement(wrapper)) - $(wrapper).writeAttribute(attributes || { }); - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); - else wrapper = new Element('div', wrapper); - if (element.parentNode) - element.parentNode.replaceChild(wrapper, element); - wrapper.appendChild(element); - return wrapper; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return $(element).recursivelyCollect('parentNode'); - }, - - descendants: function(element) { - return $(element).select("*"); - }, - - firstDescendant: function(element) { - element = $(element).firstChild; - while (element && element.nodeType != 1) element = element.nextSibling; - return $(element); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return $(element).recursivelyCollect('previousSibling'); - }, - - nextSiblings: function(element) { - return $(element).recursivelyCollect('nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return element.previousSiblings().reverse().concat(element.nextSiblings()); - }, - - match: function(element, selector) { - if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(element.parentNode); - var ancestors = element.ancestors(); - return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); - }, - - down: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? element.descendants()[expression] : - Element.select(element, expression)[index || 0]; - }, - - previous: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = element.previousSiblings(); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); - }, - - next: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = element.nextSiblings(); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); - }, - - select: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element, args); - }, - - adjacent: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element.parentNode, args).without(element); - }, - - identify: function(element) { - element = $(element); - var id = element.readAttribute('id'), self = arguments.callee; - if (id) return id; - do { id = 'anonymous_element_' + self.counter++ } while ($(id)); - element.writeAttribute('id', id); - return id; - }, - - readAttribute: function(element, name) { - element = $(element); - if (Prototype.Browser.IE) { - var t = Element._attributeTranslations.read; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - if (name.include(':')) { - return (!element.attributes || !element.attributes[name]) ? null : - element.attributes[name].value; - } - } - return element.getAttribute(name); - }, - - writeAttribute: function(element, name, value) { - element = $(element); - var attributes = { }, t = Element._attributeTranslations.write; - - if (typeof name == 'object') attributes = name; - else attributes[name] = Object.isUndefined(value) ? true : value; - - for (var attr in attributes) { - name = t.names[attr] || attr; - value = attributes[attr]; - if (t.values[attr]) name = t.values[attr](element, value); - if (value === false || value === null) - element.removeAttribute(name); - else if (value === true) - element.setAttribute(name, name); - else element.setAttribute(name, value); - } - return element; - }, - - getHeight: function(element) { - return $(element).getDimensions().height; - }, - - getWidth: function(element) { - return $(element).getDimensions().width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - return (elementClassName.length > 0 && (elementClassName == className || - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - if (!element.hasClassName(className)) - element.className += (element.className ? ' ' : '') + className; - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - element.className = element.className.replace( - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - return element[element.hasClassName(className) ? - 'removeClassName' : 'addClassName'](className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.blank(); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - - if (element.compareDocumentPosition) - return (element.compareDocumentPosition(ancestor) & 8) === 8; - - if (ancestor.contains) - return ancestor.contains(element) && ancestor !== element; - - while (element = element.parentNode) - if (element == ancestor) return true; - - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = element.cumulativeOffset(); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - style = style == 'float' ? 'cssFloat' : style.camelize(); - var value = element.style[style]; - if (!value || value == 'auto') { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } - if (style == 'opacity') return value ? parseFloat(value) : 1.0; - return value == 'auto' ? null : value; - }, - - getOpacity: function(element) { - return $(element).getStyle('opacity'); - }, - - setStyle: function(element, styles) { - element = $(element); - var elementStyle = element.style, match; - if (Object.isString(styles)) { - element.style.cssText += ';' + styles; - return styles.include('opacity') ? - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; - } - for (var property in styles) - if (property == 'opacity') element.setOpacity(styles[property]); - else - elementStyle[(property == 'float' || property == 'cssFloat') ? - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : - property] = styles[property]; - - return element; - }, - - setOpacity: function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = element.getStyle('display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (Prototype.Browser.Opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = Element.getStyle(element, 'overflow') || 'auto'; - if (element._overflow !== 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (element.getStyle('position') == 'absolute') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - var offsets = element.positionedOffset(); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (element.getStyle('position') == 'relative') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - - clonePosition: function(element, source) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || { }); - - // find page position of source - source = $(source); - var p = source.viewportOffset(); - - // find coordinate system to use - element = $(element); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(element, 'position') == 'absolute') { - parent = element.getOffsetParent(); - delta = parent.viewportOffset(); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if (options.setWidth) element.style.width = source.offsetWidth + 'px'; - if (options.setHeight) element.style.height = source.offsetHeight + 'px'; - return element; - } -}; - -Element.Methods.identify.counter = 1; - -Object.extend(Element.Methods, { - getElementsBySelector: Element.Methods.select, - childElements: Element.Methods.immediateDescendants -}); - -Element._attributeTranslations = { - write: { - names: { - className: 'class', - htmlFor: 'for' - }, - values: { } - } -}; - -if (Prototype.Browser.Opera) { - Element.Methods.getStyle = Element.Methods.getStyle.wrap( - function(proceed, element, style) { - switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; - case 'height': case 'width': - // returns '0px' for hidden elements; we want it to return null - if (!Element.visible(element)) return null; - - // returns the border-box dimensions rather than the content-box - // dimensions, so we subtract padding and borders from the value - var dim = parseInt(proceed(element, style), 10); - - if (dim !== element['offset' + style.capitalize()]) - return dim + 'px'; - - var properties; - if (style === 'height') { - properties = ['border-top-width', 'padding-top', - 'padding-bottom', 'border-bottom-width']; - } - else { - properties = ['border-left-width', 'padding-left', - 'padding-right', 'border-right-width']; - } - return properties.inject(dim, function(memo, property) { - var val = proceed(element, property); - return val === null ? memo : memo - parseInt(val, 10); - }) + 'px'; - default: return proceed(element, style); - } - } - ); - - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( - function(proceed, element, attribute) { - if (attribute === 'title') return element.title; - return proceed(element, attribute); - } - ); -} - -else if (Prototype.Browser.IE) { - // IE doesn't report offsets correctly for static elements, so we change them - // to "relative" to get the values, then change them back. - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - // IE throws an error if element is not in document - try { element.offsetParent } - catch(e) { return $(document.body) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - // Trigger hasLayout on the offset parent so that IE6 reports - // accurate offsetTop and offsetLeft values for position: fixed. - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - - Element.Methods.getStyle = function(element, style) { - element = $(element); - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); - var value = element.style[style]; - if (!value && element.currentStyle) value = element.currentStyle[style]; - - if (style == 'opacity') { - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if (value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - - if (value == 'auto') { - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) - return element['offset' + style.capitalize()] + 'px'; - return null; - } - return value; - }; - - Element.Methods.setOpacity = function(element, value) { - function stripAlpha(filter){ - return filter.replace(/alpha\([^\)]*\)/gi,''); - } - element = $(element); - var currentStyle = element.currentStyle; - if ((currentStyle && !currentStyle.hasLayout) || - (!currentStyle && element.style.zoom == 'normal')) - element.style.zoom = 1; - - var filter = element.getStyle('filter'), style = element.style; - if (value == 1 || value === '') { - (filter = stripAlpha(filter)) ? - style.filter = filter : style.removeAttribute('filter'); - return element; - } else if (value < 0.00001) value = 0; - style.filter = stripAlpha(filter) + - 'alpha(opacity=' + (value * 100) + ')'; - return element; - }; - - Element._attributeTranslations = { - read: { - names: { - 'class': 'className', - 'for': 'htmlFor' - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: function(element, attribute) { - attribute = element.getAttribute(attribute); - return attribute ? attribute.toString().slice(23, -2) : null; - }, - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; - } - } - } - }; - - Element._attributeTranslations.write = { - names: Object.extend({ - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing' - }, Element._attributeTranslations.read.names), - values: { - checked: function(element, value) { - element.checked = !!value; - }, - - style: function(element, value) { - element.style.cssText = value ? value : ''; - } - } - }; - - Element._attributeTranslations.has = {}; - - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; - Element._attributeTranslations.has[attr.toLowerCase()] = attr; - }); - - (function(v) { - Object.extend(v, { - href: v._getAttr, - src: v._getAttr, - type: v._getAttr, - action: v._getAttrNode, - disabled: v._flag, - checked: v._flag, - readonly: v._flag, - multiple: v._flag, - onload: v._getEv, - onunload: v._getEv, - onclick: v._getEv, - ondblclick: v._getEv, - onmousedown: v._getEv, - onmouseup: v._getEv, - onmouseover: v._getEv, - onmousemove: v._getEv, - onmouseout: v._getEv, - onfocus: v._getEv, - onblur: v._getEv, - onkeypress: v._getEv, - onkeydown: v._getEv, - onkeyup: v._getEv, - onsubmit: v._getEv, - onreset: v._getEv, - onselect: v._getEv, - onchange: v._getEv - }); - })(Element._attributeTranslations.read.values); -} - -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -else if (Prototype.Browser.WebKit) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - - if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { - element.width++; element.width--; - } else try { - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch (e) { } - - return element; - }; - - // Safari returns margins on body which is incorrect if the child is absolutely - // positioned. For performance reasons, redefine Element#cumulativeOffset for - // KHTML/WebKit only. - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; -} - -if (Prototype.Browser.IE || Prototype.Browser.Opera) { - // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements - Element.Methods.update = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - - content = Object.toHTML(content); - var tagName = element.tagName.toUpperCase(); - - if (tagName in Element._insertionTranslations.tags) { - $A(element.childNodes).each(function(node) { element.removeChild(node) }); - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { element.appendChild(node) }); - } - else element.innerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -if ('outerHTML' in document.createElement('div')) { - Element.Methods.replace = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - element.parentNode.replaceChild(content, element); - return element; - } - - content = Object.toHTML(content); - var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); - - if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - parent.removeChild(element); - if (nextSibling) - fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); - else - fragments.each(function(node) { parent.appendChild(node) }); - } - else element.outerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -Element._returnOffset = function(l, t) { - var result = [l, t]; - result.left = l; - result.top = t; - return result; -}; - -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; - return $A(div.childNodes); -}; - -Element._insertionTranslations = { - before: function(element, node) { - element.parentNode.insertBefore(node, element); - }, - top: function(element, node) { - element.insertBefore(node, element.firstChild); - }, - bottom: function(element, node) { - element.appendChild(node); - }, - after: function(element, node) { - element.parentNode.insertBefore(node, element.nextSibling); - }, - tags: { - TABLE: ['
     '+(serie.label || String.fromCharCode(65+i))+'
    ', '
    ', 1], - TBODY: ['', '
    ', 2], - TR: ['', '
    ', 3], - TD: ['
    ', '
    ', 4], - SELECT: ['', 1] - } -}; - -(function() { - Object.extend(this.tags, { - THEAD: this.tags.TBODY, - TFOOT: this.tags.TBODY, - TH: this.tags.TD - }); -}).call(Element._insertionTranslations); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - attribute = Element._attributeTranslations.has[attribute] || attribute; - var node = $(element).getAttributeNode(attribute); - return !!(node && node.specified); - } -}; - -Element.Methods.ByTag = { }; - -Object.extend(Element, Element.Methods); - -if (!Prototype.BrowserFeatures.ElementExtensions && - document.createElement('div')['__proto__']) { - window.HTMLElement = { }; - window.HTMLElement.prototype = document.createElement('div')['__proto__']; - Prototype.BrowserFeatures.ElementExtensions = true; -} - -Element.extend = (function() { - if (Prototype.BrowserFeatures.SpecificElementExtensions) - return Prototype.K; - - var Methods = { }, ByTag = Element.Methods.ByTag; - - var extend = Object.extend(function(element) { - if (!element || element._extendedByPrototype || - element.nodeType != 1 || element == window) return element; - - var methods = Object.clone(Methods), - tagName = element.tagName.toUpperCase(), property, value; - - // extend methods for specific tags - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - - for (property in methods) { - value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } - - element._extendedByPrototype = Prototype.emptyFunction; - return element; - - }, { - refresh: function() { - // extend methods for all tags (Safari doesn't need this) - if (!Prototype.BrowserFeatures.ElementExtensions) { - Object.extend(Methods, Element.Methods); - Object.extend(Methods, Element.Methods.Simulated); - } - } - }); - - extend.refresh(); - return extend; -})(); - -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; - -Element.addMethods = function(methods) { - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; - - if (!methods) { - Object.extend(Form, Form.Methods); - Object.extend(Form.Element, Form.Element.Methods); - Object.extend(Element.Methods.ByTag, { - "FORM": Object.clone(Form.Methods), - "INPUT": Object.clone(Form.Element.Methods), - "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) - }); - } - - if (arguments.length == 2) { - var tagName = methods; - methods = arguments[1]; - } - - if (!tagName) Object.extend(Element.Methods, methods || { }); - else { - if (Object.isArray(tagName)) tagName.each(extend); - else extend(tagName); - } - - function extend(tagName) { - tagName = tagName.toUpperCase(); - if (!Element.Methods.ByTag[tagName]) - Element.Methods.ByTag[tagName] = { }; - Object.extend(Element.Methods.ByTag[tagName], methods); - } - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - for (var property in methods) { - var value = methods[property]; - if (!Object.isFunction(value)) continue; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = value.methodize(); - } - } - - function findDOMClass(tagName) { - var klass; - var trans = { - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": - "FrameSet", "IFRAME": "IFrame" - }; - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName.capitalize() + 'Element'; - if (window[klass]) return window[klass]; - - window[klass] = { }; - window[klass].prototype = document.createElement(tagName)['__proto__']; - return window[klass]; - } - - if (F.ElementExtensions) { - copy(Element.Methods, HTMLElement.prototype); - copy(Element.Methods.Simulated, HTMLElement.prototype, true); - } - - if (F.SpecificElementExtensions) { - for (var tag in Element.Methods.ByTag) { - var klass = findDOMClass(tag); - if (Object.isUndefined(klass)) continue; - copy(T[tag], klass.prototype); - } - } - - Object.extend(Element, Element.Methods); - delete Element.ByTag; - - if (Element.extend.refresh) Element.extend.refresh(); - Element.cache = { }; -}; - -document.viewport = { - getDimensions: function() { - var dimensions = { }, B = Prototype.Browser; - $w('width height').each(function(d) { - var D = d.capitalize(); - if (B.WebKit && !document.evaluate) { - // Safari <3.0 needs self.innerWidth/Height - dimensions[d] = self['inner' + D]; - } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { - // Opera <9.5 needs document.body.clientWidth/Height - dimensions[d] = document.body['client' + D] - } else { - dimensions[d] = document.documentElement['client' + D]; - } - }); - return dimensions; - }, - - getWidth: function() { - return this.getDimensions().width; - }, - - getHeight: function() { - return this.getDimensions().height; - }, - - getScrollOffsets: function() { - return Element._returnOffset( - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); - } -}; -/* Portions of the Selector class are derived from Jack Slocum's DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ - -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); - - if (this.shouldUseSelectorsAPI()) { - this.mode = 'selectorsAPI'; - } else if (this.shouldUseXPath()) { - this.mode = 'xpath'; - this.compileXPathMatcher(); - } else { - this.mode = "normal"; - this.compileMatcher(); - } - - }, - - shouldUseXPath: function() { - if (!Prototype.BrowserFeatures.XPath) return false; - - var e = this.expression; - - // Safari 3 chokes on :*-of-type and :empty - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - // XPath can't do namespaced attributes, nor can it read - // the "checked" property from DOM nodes - if ((/(\[[\w-]*?:|:checked)/).test(e)) - return false; - - return true; - }, - - shouldUseSelectorsAPI: function() { - if (!Prototype.BrowserFeatures.SelectorsAPI) return false; - - if (!Selector._div) Selector._div = new Element('div'); - - // Make sure the browser treats the selector as valid. Test on an - // isolated element to minimize cost of this check. - try { - Selector._div.querySelector(this.expression); - } catch(e) { - return false; - } - - return true; - }, - - compileMatcher: function() { - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m; - - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } - - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; - - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : - new Template(c[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.matcher.push("return h.unique(n);\n}"); - eval(this.matcher.join('\n')); - Selector._cache[this.expression] = this.matcher; - }, - - compileXPathMatcher: function() { - var e = this.expression, ps = Selector.patterns, - x = Selector.xpath, le, m; - - if (Selector._cache[e]) { - this.xpath = Selector._cache[e]; return; - } - - this.matcher = ['.//*']; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - if (m = e.match(ps[i])) { - this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : - new Template(x[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.xpath = this.matcher.join(''); - Selector._cache[this.expression] = this.xpath; - }, - - findElements: function(root) { - root = root || document; - var e = this.expression, results; - - switch (this.mode) { - case 'selectorsAPI': - // querySelectorAll queries document-wide, then filters to descendants - // of the context element. That's not what we want. - // Add an explicit context to the selector if necessary. - if (root !== document) { - var oldId = root.id, id = $(root).identify(); - e = "#" + id + " " + e; - } - - results = $A(root.querySelectorAll(e)).map(Element.extend); - root.id = oldId; - - return results; - case 'xpath': - return document._getElementsByXPath(this.xpath, root); - default: - return this.matcher(root); - } - }, - - match: function(element) { - this.tokens = []; - - var e = this.expression, ps = Selector.patterns, as = Selector.assertions; - var le, p, m; - - while (e && le !== e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - // use the Selector.assertions methods unless the selector - // is too complex. - if (as[i]) { - this.tokens.push([i, Object.clone(m)]); - e = e.replace(m[0], ''); - } else { - // reluctantly do a document-wide search - // and look for a match in the array - return this.findElements(document).include(element); - } - } - } - } - - var match = true, name, matches; - for (var i = 0, token; token = this.tokens[i]; i++) { - name = token[0], matches = token[1]; - if (!Selector.assertions[name](element, matches)) { - match = false; break; - } - } - - return match; - }, - - toString: function() { - return this.expression; - }, - - inspect: function() { - return "#"; - } -}); - -Object.extend(Selector, { - _cache: { }, - - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0)]", - 'checked': "[@checked]", - 'disabled': "[(@disabled) and (@type!='hidden')]", - 'enabled': "[not(@disabled) and (@type!='hidden')]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v; - - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in p) { - if (m = e.match(p[i])) { - v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); - exclusion.push("(" + v.substring(1, v.length - 1) + ")"); - e = e.replace(m[0], ''); - break; - } - } - } - return "[not(" + exclusion.join(" and ") + ")]"; - }, - 'nth-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); - }, - 'nth-last-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); - }, - 'nth-of-type': function(m) { - return Selector.xpath.pseudos.nth("position() ", m); - }, - 'nth-last-of-type': function(m) { - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); - }, - 'first-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); - }, - 'last-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); - }, - 'only-of-type': function(m) { - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); - }, - nth: function(fragment, m) { - var mm, formula = m[6], predicate; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - if (mm = formula.match(/^(\d+)$/)) // digit only - return '[' + fragment + "= " + mm[1] + ']'; - if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (mm[1] == "-") mm[1] = -1; - var a = mm[1] ? Number(mm[1]) : 1; - var b = mm[2] ? Number(mm[2]) : 0; - predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + - "((#{fragment} - #{b}) div #{a} >= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } - } - }, - - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: { - // combinators must be listed first - // (and descendant needs to be last combinator) - laterSibling: /^\s*~\s*/, - child: /^\s*>\s*/, - adjacent: /^\s*\+\s*/, - descendant: /^\s/, - - // selectors follow - tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, - id: /^#([\w\-\*]+)(\b|$)/, - className: /^\.([\w\-\*]+)(\b|$)/, - pseudo: -/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, - attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, - attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ - }, - - // for Selector.match and Element#match - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); - } - }, - - handlers: { - // UTILITY FUNCTIONS - // joins two collections - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, - - // marks an array of nodes for counting - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, - - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = undefined; - return nodes; - }, - - // mark each child node with its position (for nth calls) - // "ofType" flag indicates whether we're indexing for nth-of-type - // rather than nth-child - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - // filters out duplicates and extends all nodes - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (!(n = nodes[i])._countedByPrototype) { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); - }, - - // COMBINATOR FUNCTIONS - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); - } - return results; - }, - - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - // TOKEN FUNCTIONS - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - // fastlane for ordinary descendant combinators - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - if (!targetNode) return []; - if (!nodes && root == document) return [targetNode]; - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); - } - }, - - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - // handles the an+b logic - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - // IE treats comments as element nodes - if (node.tagName == '!' || node.firstChild) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled && (!node.type || node.type !== 'hidden')) - results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, - '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, - '$=': function(nv, v) { return nv.endsWith(v); }, - '*=': function(nv, v) { return nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + - '-').include('-' + (v || "").toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; - } -}); - -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - // IE returns comment nodes on getElementsByTagName("*"). - // Filter them out. - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - }, - - // IE improperly serializes _countedByPrototype in (inner|outer)HTML. - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } - }); -} - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} -var Form = { - reset: function(form) { - $(form).reset(); - return form; - }, - - serializeElements: function(elements, options) { - if (typeof options != 'object') options = { hash: !!options }; - else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; - - var data = elements.inject({ }, function(result, element) { - if (!element.disabled && element.name) { - key = element.name; value = $(element).getValue(); - if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && - submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - // a key is already present; construct an array of values - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return options.hash ? data : Object.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, options) { - return Form.serializeElements(Form.getElements(form), options); - }, - - getElements: function(form) { - return $A($(form).getElementsByTagName('*')).inject([], - function(elements, child) { - if (Form.Element.Serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - } - ); - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - Form.getElements(form).invoke('disable'); - return form; - }, - - enable: function(form) { - form = $(form); - Form.getElements(form).invoke('enable'); - return form; - }, - - findFirstElement: function(form) { - var elements = $(form).getElements().findAll(function(element) { - return 'hidden' != element.type && !element.disabled; - }); - var firstByIndex = elements.findAll(function(element) { - return element.hasAttribute('tabIndex') && element.tabIndex >= 0; - }).sortBy(function(element) { return element.tabIndex }).first(); - - return firstByIndex ? firstByIndex : elements.find(function(element) { - return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - }, - - request: function(form, options) { - form = $(form), options = Object.clone(options || { }); - - var params = options.parameters, action = form.readAttribute('action') || ''; - if (action.blank()) action = window.location.href; - options.parameters = form.serialize(true); - - if (params) { - if (Object.isString(params)) params = params.toQueryParams(); - Object.extend(options.parameters, params); - } - - if (form.hasAttribute('method') && !options.method) - options.method = form.method; - - return new Ajax.Request(action, options); - } -}; - -/*--------------------------------------------------------------------------*/ - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -}; - -Form.Element.Methods = { - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = { }; - pair[element.name] = value; - return Object.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - setValue: function(element, value) { - element = $(element); - var method = element.tagName.toLowerCase(); - Form.Element.Serializers[method](element, value); - return element; - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - try { - element.focus(); - if (element.select && (element.tagName.toLowerCase() != 'input' || - !['button', 'reset', 'submit'].include(element.type))) - element.select(); - } catch (e) { } - return element; - }, - - disable: function(element) { - element = $(element); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.disabled = false; - return element; - } -}; - -/*--------------------------------------------------------------------------*/ - -var Field = Form.Element; -var $F = Form.Element.Methods.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element, value) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element, value); - default: - return Form.Element.Serializers.textarea(element, value); - } - }, - - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; - else element.checked = !!value; - }, - - textarea: function(element, value) { - if (Object.isUndefined(value)) return element.value; - else element.value = value; - }, - - select: function(element, value) { - if (Object.isUndefined(value)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, currentValue, single = !Object.isArray(value); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - currentValue = this.optionValue(opt); - if (single) { - if (currentValue == value) { - opt.selected = true; - return; - } - } - else opt.selected = value.include(currentValue); - } - } - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - // extend element because hasAttribute may not be native - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -}; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = Class.create(PeriodicalExecuter, { - initialize: function($super, element, frequency, callback) { - $super(callback, frequency); - this.element = $(element); - this.lastValue = this.getValue(); - }, - - execute: function() { - var value = this.getValue(); - if (Object.isString(this.lastValue) && Object.isString(value) ? - this.lastValue != value : String(this.lastValue) != String(value)) { - this.callback(this.element, value); - this.lastValue = value; - } - } -}); - -Form.Element.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = Class.create({ - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback, this); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -}); - -Form.Element.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) var Event = { }; - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, - - cache: { }, - - relatedTarget: function(event) { - var element; - switch(event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } -}); - -Event.Methods = (function() { - var isButton; - - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - isButton = function(event, code) { - return event.button == buttonMap[code]; - }; - - } else if (Prototype.Browser.WebKit) { - isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - - } else { - isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - return { - isLeftClick: function(event) { return isButton(event, 0) }, - isMiddleClick: function(event) { return isButton(event, 1) }, - isRightClick: function(event) { return isButton(event, 2) }, - - element: function(event) { - event = Event.extend(event); - - var node = event.target, - type = event.type, - currentTarget = event.currentTarget; - - if (currentTarget && currentTarget.tagName) { - // Firefox screws up the "click" event when moving between radio buttons - // via arrow keys. It also screws up the "load" and "error" events on images, - // reporting the document as the target instead of the original image. - if (type === 'load' || type === 'error' || - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' - && currentTarget.type === 'radio')) - node = currentTarget; - } - if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; - return Element.extend(node); - }, - - findElement: function(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - }, - - pointer: function(event) { - var docElement = document.documentElement, - body = document.body || { scrollLeft: 0, scrollTop: 0 }; - return { - x: event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)), - y: event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)) - }; - }, - - pointerX: function(event) { return Event.pointer(event).x }, - pointerY: function(event) { return Event.pointer(event).y }, - - stop: function(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - event.stopped = true; - } - }; -})(); - -Event.extend = (function() { - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { - m[name] = Event.Methods[name].methodize(); - return m; - }); - - if (Prototype.Browser.IE) { - Object.extend(methods, { - stopPropagation: function() { this.cancelBubble = true }, - preventDefault: function() { this.returnValue = false }, - inspect: function() { return "[object Event]" } - }); - - return function(event) { - if (!event) return false; - if (event._extendedByPrototype) return event; - - event._extendedByPrototype = Prototype.emptyFunction; - var pointer = Event.pointer(event); - Object.extend(event, { - target: event.srcElement, - relatedTarget: Event.relatedTarget(event), - pageX: pointer.x, - pageY: pointer.y - }); - return Object.extend(event, methods); - }; - - } else { - Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; - Object.extend(Event.prototype, methods); - return Prototype.K; - } -})(); - -Object.extend(Event, (function() { - var cache = Event.cache; - - function getEventID(element) { - if (element._prototypeEventID) return element._prototypeEventID[0]; - arguments.callee.id = arguments.callee.id || 1; - return element._prototypeEventID = [++arguments.callee.id]; - } - - function getDOMEventName(eventName) { - if (eventName && eventName.include(':')) return "dataavailable"; - return eventName; - } - - function getCacheForID(id) { - return cache[id] = cache[id] || { }; - } - - function getWrappersForEventName(id, eventName) { - var c = getCacheForID(id); - return c[eventName] = c[eventName] || []; - } - - function createWrapper(element, eventName, handler) { - var id = getEventID(element); - var c = getWrappersForEventName(id, eventName); - if (c.pluck("handler").include(handler)) return false; - - var wrapper = function(event) { - if (!Event || !Event.extend || - (event.eventName && event.eventName != eventName)) - return false; - - Event.extend(event); - handler.call(element, event); - }; - - wrapper.handler = handler; - c.push(wrapper); - return wrapper; - } - - function findWrapper(id, eventName, handler) { - var c = getWrappersForEventName(id, eventName); - return c.find(function(wrapper) { return wrapper.handler == handler }); - } - - function destroyWrapper(id, eventName, handler) { - var c = getCacheForID(id); - if (!c[eventName]) return false; - c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); - } - - function destroyCache() { - for (var id in cache) - for (var eventName in cache[id]) - cache[id][eventName] = null; - } - - - // Internet Explorer needs to remove event handlers on page unload - // in order to avoid memory leaks. - if (window.attachEvent) { - window.attachEvent("onunload", destroyCache); - } - - // Safari has a dummy event handler on page unload so that it won't - // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" - // object when page is returned to via the back button using its bfcache. - if (Prototype.Browser.WebKit) { - window.addEventListener('unload', Prototype.emptyFunction, false); - } - - return { - observe: function(element, eventName, handler) { - element = $(element); - var name = getDOMEventName(eventName); - - var wrapper = createWrapper(element, eventName, handler); - if (!wrapper) return element; - - if (element.addEventListener) { - element.addEventListener(name, wrapper, false); - } else { - element.attachEvent("on" + name, wrapper); - } - - return element; - }, - - stopObserving: function(element, eventName, handler) { - element = $(element); - var id = getEventID(element), name = getDOMEventName(eventName); - - if (!handler && eventName) { - getWrappersForEventName(id, eventName).each(function(wrapper) { - element.stopObserving(eventName, wrapper.handler); - }); - return element; - - } else if (!eventName) { - Object.keys(getCacheForID(id)).each(function(eventName) { - element.stopObserving(eventName); - }); - return element; - } - - var wrapper = findWrapper(id, eventName, handler); - if (!wrapper) return element; - - if (element.removeEventListener) { - element.removeEventListener(name, wrapper, false); - } else { - element.detachEvent("on" + name, wrapper); - } - - destroyWrapper(id, eventName, handler); - - return element; - }, - - fire: function(element, eventName, memo) { - element = $(element); - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent("HTMLEvents"); - event.initEvent("dataavailable", true, true); - } else { - event = document.createEventObject(); - event.eventType = "ondataavailable"; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) { - element.dispatchEvent(event); - } else { - element.fireEvent(event.eventType, event); - } - - return Event.extend(event); - } - }; -})()); - -Object.extend(Event, Event.Methods); - -Element.addMethods({ - fire: Event.fire, - observe: Event.observe, - stopObserving: Event.stopObserving -}); - -Object.extend(document, { - fire: Element.Methods.fire.methodize(), - observe: Element.Methods.observe.methodize(), - stopObserving: Element.Methods.stopObserving.methodize(), - loaded: false -}); - -(function() { - /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards and John Resig. */ - - var timer; - - function fireContentLoadedEvent() { - if (document.loaded) return; - if (timer) window.clearInterval(timer); - document.fire("dom:loaded"); - document.loaded = true; - } - - if (document.addEventListener) { - if (Prototype.Browser.WebKit) { - timer = window.setInterval(function() { - if (/loaded|complete/.test(document.readyState)) - fireContentLoadedEvent(); - }, 0); - - Event.observe(window, "load", fireContentLoadedEvent); - - } else { - document.addEventListener("DOMContentLoaded", - fireContentLoadedEvent, false); - } - - } else { - document.write("