diff --git a/frontend/images/information.png b/frontend/images/information.png new file mode 100644 index 0000000..12cd1ae Binary files /dev/null and b/frontend/images/information.png differ diff --git a/frontend/images/zoom.png b/frontend/images/zoom.png new file mode 100644 index 0000000..908612e Binary files /dev/null and b/frontend/images/zoom.png differ diff --git a/frontend/images/zoom_in.png b/frontend/images/zoom_in.png new file mode 100644 index 0000000..cdf0a52 Binary files /dev/null and b/frontend/images/zoom_in.png differ diff --git a/frontend/images/zoom_out.png b/frontend/images/zoom_out.png new file mode 100644 index 0000000..07bf98a Binary files /dev/null and b/frontend/images/zoom_out.png differ diff --git a/frontend/index.html b/frontend/index.html index dc49af7..ed36a9b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -14,9 +14,8 @@ - - + @@ -24,7 +23,7 @@ - + @@ -35,12 +34,19 @@ - + + -
- - + + + + + + + + +
@@ -54,6 +60,9 @@ Typ Operationen Anzeige + Min. + Max. + Avg. diff --git a/frontend/javascripts/functions.js b/frontend/javascripts/functions.js index 00f5277..ed7ac18 100644 --- a/frontend/javascripts/functions.js +++ b/frontend/javascripts/functions.js @@ -38,19 +38,39 @@ function refreshWindow() { } } -function moveWindow(mode) { - delta = myWindowEnd - myWindowStart; +// alter plotting range (for WUI) +function plot() { + delta = vz.to - vz.from; - if(mode == 'last') - myWindowEnd = (new Date()).getTime(); - myWindowStart = myWindowEnd - delta; - if(mode == 'back') { - myWindowStart -= delta; - myWindowEnd -= delta; - } - if(mode == 'forward') { - myWindowStart += delta; - myWindowEnd += delta; + switch(this.value) { + case 'move_last': + vz.to = (new Date()).getTime(); + vz.from = vz.to - delta; + break; + + case 'move_back': + vz.from -= delta; + vz.to -= delta; + break; + case 'move_forward': + vz.from += delta; + vz.to += delta; + break; + + case 'zoom_reset': + // TODO + break; + + case 'zoom_in': + // TODO + break; + + case 'zoom_out': + // TODO + break; + + case 'refresh': + // do nothing; just loadData() } loadData(); @@ -58,58 +78,30 @@ function moveWindow(mode) { //load json data with given time window function loadData() { - eachRecursive(entities, function(entity, parent) { + eachRecursive(vz.entities, function(entity, parent) { if (entity.active && entity.type != 'group') { - $.getJSON(backendUrl + '/data/' + entity.uuid + '.json', { from: myWindowStart, to: myWindowEnd, tuples: tuples }, ajaxWait(function(json) { + $.getJSON(vz.options.backendUrl + '/data/' + entity.uuid + '.json', { from: vz.from, to: vz.to, tuples: vz.options.tuples }, ajaxWait(function(json) { entity.data = json.data[0]; // TODO filter for correct uuid - }, showChart, 'data')); + }, drawPlot, 'data')); } }); } -function showChart() { - var jqData = new Array(); +function drawPlot() { + //vz.plot.axes.xaxis.min = vz.from; + //vz.plot.axes.xaxis.min = vz.to; - eachRecursive(entities, function(entity, parent) { - jqData.push(entity.data.tuples); + var i = 0; + + eachRecursive(vz.entities, function(entity, parent) { + vz.plot.series[i++].data = entity.data.tuples; }); - - // TODO read docs - chart = $.jqplot('plot', jqData, jqOptions); - chart.replot({ - clear: true, + + vz.plot.replot({ resetAxes: true }); } -/* - * Cookie & UUID related functions - */ -function getUUIDs() { - if ($.getCookie('uuids')) { - return JSON.parse($.getCookie('uuids')); - } - else { - return new Array; - } -} - -function addUUID(uuid) { - if (!uuids.contains(uuid)) { - uuids.push(uuid); - $.setCookie('uuids', JSON.stringify(uuids)); - } -} - -function removeUUID(uuid) { - if (uuids.contains(uuid)) { - uuids.filter(function(value) { - return value != uuid; - }); - $.setCookie('uuids', JSON.stringify(uuids)); - } -} - /* * Entity list related functions */ @@ -117,10 +109,10 @@ function removeUUID(uuid) { /** * Get all entity information from backend */ -function loadEntities(uuids) { - $.each(uuids, function(index, value) { - $.getJSON(backendUrl + '/entity/' + value + '.json', ajaxWait(function(json) { - entities.push(json.entity); +function loadEntities() { + $.each(vz.uuids, function(index, value) { + $.getJSON(vz.options.backendUrl + '/entity/' + value + '.json', ajaxWait(function(json) { + vz.entities.push(json.entity); }, showEntities, 'information')); }); } @@ -134,9 +126,9 @@ function showEntities() { var i = 0; - eachRecursive(entities, function(entity, parent) { + eachRecursive(vz.entities, function(entity, parent) { entity.active = true; // TODO active by default or via backend property? - entity.color = colors[i++%colors.length]; + entity.color = vz.options.plot.seriesColors[i++ % vz.options.plot.seriesColors.length]; $('#entities tbody').append( $('') @@ -152,6 +144,12 @@ function showEntities() { ) .append($('').text(entity.type)) .append($('') // operations + .append($('') + .attr('type', 'image') + .attr('src', 'images/information.png') + .attr('alt', 'details') + .bind('click', entity, function(event) { showEntityDetails(event.data); }) + ) .append($('') .attr('type', 'image') .attr('src', 'images/delete.png') @@ -183,6 +181,59 @@ function showEntities() { loadData(); } +function showEntityDetails(entity) { + var properties = $(''); + + $.each(entity, function(key, value) { + properties.append($('') + .append($('","
') + .addClass('key') + .text(key) + ) + .append($('') + .addClass('value') + .text(value) + ) + ); + }); + + $('
') + .addClass('details') + .append(properties) + .dialog({ + title: 'Entity Details', + width: 450 + }); +} + +/* + * Cookie & UUID related functions + */ +function getUUIDs() { + if ($.getCookie('uuids')) { + return JSON.parse($.getCookie('uuids')); + } + else { + return new Array(); + } +} + +function addUUID(uuid) { + if (!uuids.contains(uuid)) { + uuids.push(uuid); + $.setCookie('uuids', JSON.stringify(uuids)); + } +} + +function removeUUID(uuid) { + if (uuids.contains(uuid)) { + uuids.filter(function(value) { + return value != uuid; + }); + $.setCookie('uuids', JSON.stringify(uuids)); + } +} + /* * General helper functions */ @@ -212,18 +263,48 @@ function eachRecursive(array, callback, parent) { }); } +/** + * Checks if value of part of the array + * + * @param needle the value to search for + * @return boolean + */ Array.prototype.contains = function(needle) { - for (var i=0; i. - -Downloads can be found at . - -The mailing list is at . - -Examples and unit tests are at . - -Documentation is at . - -The project page and source code are at . - -Bugs, issues, feature requests: . - -Basic Usage Instructions: - -jqPlot requires jQuery (tested with 1.3.2 or better). jQuery 1.3.2 is included in -the distribution. To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and -optionally the excanvas script for IE support in your web page... - -> -> -> -> - -For usage instructions, see in usage.txt. For available options, see - in jqPlotOptions.txt. - -Building from source: - -To build a distribution from source you need to have ant -installed. There are 6 targets: clean, dist, min, tests, docs and all. Use - -> ant -p - -to get a description of the various build targets. diff --git a/frontend/javascripts/jqplot/changes.txt b/frontend/javascripts/jqplot/changes.txt deleted file mode 100644 index 3095b7a..0000000 --- a/frontend/javascripts/jqplot/changes.txt +++ /dev/null @@ -1,261 +0,0 @@ -Title: Change Log - -0.9.7: - -* Added Mekko chart plot type with enhanced legend and axes support. -* Implemented vertical waterfall charts. Can create waterfall plot as - option to bar chart. See examples folder of distribution. -* Enhanced plot labels for waterfall style. -* Enhanced bar plots so you can now color each bar of a series - independently with the "varyBarColor" option. -* Refactored series drawing so that each series and series shadow drawn - on it's own canvas. Allows series to be redrawn independently of eachother. -* Added additional default series colors. -* Aded useNegativeColors option to turn off negative color array and use - only seriesColors array to define all bar/filled line colors. -* Fix css for cursor legend. -* Modified shape renderer so rectangles can be stroked and filled. -* Refactored date methods out of dateAxisRenderer so that date formatter - and methods can be accesses outside of dateAxisRenderer plugin. -* Fixed #132, now trigger series change event on plot target instead of drag canvas. -* Fixes issue #116 where some source files had mix of tabs and spaces - for indentation. Should have been all spaces. -* Fixed issue #126, some links broken in docs section of web site. -* Fixed issue #90, trendline plugin incompatibility with pie renderer. -* Updated samples in examples folder of distribution to include navigation - links if web server is set up to process .html files with php. - - -0.9.6: - -* New, easier to use, replot() method for placing plots in tabs, accordions, - resizable containers or for changing plot parameters programmatically. -* Updated legend renderer for pie charts to draw swatches which will - print correctly. -* Fixed issue #118 with patch from taum so autoscale option will - honor tickInterval and numberTicks options -* Fix to plot diameter calculation for initially hidden plots. -* Added examples for making plots in jQuery UI tabs and accordions. -* Fixed issue #120 where pie chart with single slice not displaying - correctly in IE and Chrome - - -0.9.5.2: - -* Fixed #102 where double clicking on plot that has zoom enabled, but - has not been zoomed resulted in error. -* Fixed bug where candlestick coloring options not working. -* Added option to turn individual series labels off in the legend. - - -0.9.5.1: - -* Fixed bug where tooltip not working with OHLC and candlestick charts. -* Added additional marker styles: plus, X and dash. - - -0.9.5: - -* Implemented "zoomProxy". zoomProxy allows zooming one plot from another - such as an overview plot. -* Zooming can now be constrained to just x or y axis. -* Enhanced cursor plugin with vertical "dataTracking" line. This is a line - at the cursor location with a readout of data points at the line location - which are displayed in the chart legend. -* Changed cursor tooltip format string. Now one format string is used for - entire tooptip. -* Added mechanisms to specify plot size when plot target is hidden or plot - height/width otherwise cannot be determined from markup. -* Added $.jqplot.config object to specify jqplot wide configuraiton options. - These include enablePlugins to globally set the default plugin state on/off - and defaultHeight/defaultWidth to specify default plot height/width. -* Added fillToZero option which forces filled charts to fill to zero as opposed - to axis minimum. Thus negative filled bar/line values will fill upwards to - zero axis value. -* Added option to disable stacking on individual lines. -* Changed targetId property of the plot object so it now includes a "#" before - the id string. -* Improved tick and body sizing of Open Hi Low Close and candlestick charts. -* Removed lots of web site related files from the repository. This means that, - if working from the sources, user's won't be able to build the jqplot web - site and the docs/tests that are hosted on that site. The minified and - compressed distribution packages will build fine. -* Lots of examples were added to a separate examples directory to better show - functionality of jqPlot for local testing with the distribution. -* Many various bug fixes and other minor enhancements. - - -0.9.4: - -* Implemented axis labels. Labels can be rendered in div tags or as canvas - elements supporting rotated text. -* Improved rotated axis label positioning so labels will start or end at a - tick position. -* Fixed bug where an empty data series would hang plot rendering. -* completed issue #66 for misc. improvements to documentation. -* Fixed issue #64 where the same ID's were assigned to cursor and highlighter - elements. -* Added option to legend to encode special HTML characters. -* Fixed undesirable behavior where point labels for points off the plot - were being rendered. -* Added edgeTolerance option to point label renderer to control rendering of - labels near plot edges. - - -0.9.3: - -* Preliminary support for axis labels. Currently rendered into DIV tags, - so no ratated label support. This feature is currently expreimental. -* Fixed bug #52, needed space in tick div tag between style and class declarations - or plot failed in certain application doctypes. -* Fixed issue #54, miter style line join for chart lines causing spikes at steep - changes in slope. Changed miter style to round. -* Added examples for new autoscaling algorithm. -* Fixed bug #57, category axis labels disappear on redraw() -* Improved algorithm which controlled maximum number of labels that would display - on a category axis. -* Fixed bug #45 where null values causing errors in plotData and gridData. -* Fixed issue #60 where seriesColors option was not working. - - -0.9.2: - -* Fixed bug #45 where a plot could crash if series had different numbers of points. -* Fixed issue #50, added option to turn off sorting of series data. -* Fixed issue #31, implemented a better axis autoscaling algorithm and added an autoscale option. - -0.9.1: - -* Fixed bug #40, when axis pad, padMax, padMin set to 0, graph would fail to render. -* Fixed bug #41 where pie and bar charts not rendered correctly on redraw(). -* Fixed bug #11, filled stacked line plots not rendering correctly in IE. -* Fixed bug #42 where stacked charts not rendering with string date axis ticks. -* Fixed bug in redraw() method where axes ticks were not reset. -* Fixed "jqplotPreRedrawEvent" that should have been named "jqplotPostRedraw" event. - -0.9.0: - -* Added Open Hi Low Close charts, Candlestick charts and Hi Low Close charts. -* Added support for arbitrary labels on the data points. -* Enhanced highlighter plugin to allow custom formatting control of entire tooltip. -* Enhanced highlighter to support multiple y values in a data point. -* Fixed bug #38 where series with a single point with a negative value would fail. -* Improvements to examples to show what plugins to include. -* Expanded documentation for some of the plugins. - -0.8.5: - -* Added zooming ability with double click or single click options to reset zoom. -* Modified default tick spacing algorithm for date axes to give more space to ticks. -* Fixed bug #2 where tickInterval wasn't working properly. -* Added neighborThreshold option to control how close mouse must be to - point to trigger neighbor detection. -* Added double click event handler on plot. - -0.8.0: - -* Support for up to 9 y axes. -* Added option to control padding at max/min bounds of axes separately. -* Closed issue #21, added options to control grid line color and width. -* Closed issue #20, added options to filled line charts to stoke above - fill and customize fill color and transparency. -* Improved structure of on line documentation to make usage and options - docs default. -* Added much documentation on options and css styling. - -0.7.1: - -* Bug fix release -* Fixed bug #6, missing semi-colons messing up some javascript compressors. -* Fixed bug #13 where 2D ticks array of [values, labels] would fail to - renderer with DateAxisRenderer. -* Fixes bug #16 where pie renderer overwriting options for all plot types - and crashing non pie plots. -* Fixes bug #17 constrainTo dragable option mispelled as "contstrainTo". - Fixed dragable color issue when used with trend lines. - -0.7.0: - -* Pie chart support -* Enabled tooltipLocation option in highlighter. -* Highlighter Tooltip will account for mark size and highlight size when - positioning itself. -* Added ability to show just x, y or both axes in highlighter tooltip. -* Added customization of separator between axes values in highlighter tooltip. -* Modified how shadows are drawn for lines, bars and markers. Now drawn first, - so they are always behind the object. -* Adjustments to shadow parameters on lines to account for new shadow positioning. -* Added a ColorGenerator class to robustly return next available color - for a plot with wrap around to first color at end. -* Udates to docs about css file. -* Fixed bug with String x values in series and IE error on sorting (Category Axis). -* Added cursor changes in dragable plugin when cursor near dragable point. - -0.6.6b: - -* Added excanvas.js and excanvas.min.js to compressed distributions. -* Added example/test html pages I had locally into repository and to - compressed distributions. - -0.6.6a: - -* Removed absolute positioning from dom element and put back into css file. -* Duplicate of 0.6.6 with a suffix to unambiguously differentiate between - previously posted 0.6.6 release. - -0.6.6: - -* Fixed bug #5, trend line plugin failing when no trend line options specified. -* Added absolute position css spec to axis tick dom element. -* Enhancement to category axes, more intuitive handling of series with - missing data values. - -0.6.5: - -* Fixed bug #4, series of unequal data length not rendering correctly. - This is a bugfix release only. - -0.6.4: - -* Fixed bug (issue #1 in tracker) where flat line data series (all x and/or y - values are euqal) or single value data series would crash. - -0.6.3: - -* Support for stacked line (a.k.a. area) and stacked bar (horizontal and - vertical) charts. -* Refactored barRenderer to use default shape and shadow renderers. -* Added info (contacts & support information) page to web site. - -0.6.2: - -* This is a minor upgrade to docs and build only. No functionality has changed. -* Ant build script generates entire site, examples, tests and distribution. -* Improvements to documentation. - -0.6.1: - -* New sprintf implementation from Ash Searle that implements %g. -* Fix to sprintf e/f formats. -* Created new format specifier, %p and %P to preserve significance. -* Modified p/P format to better display larger numbers. -* Fixed and simplified significant digits calculation for sprintf. -* Added option to have cursor tooltip follow the mouse or not. -* Added options to change size of highlight. -* Updates to handle dates like '6-May-09'. -* Mods to improve look of web site. -* Updates to documentation. -* Added license and copyright statement to source files. - -0.6.0: - -* Added rotated text support. Uses native canvas text functionality in - browsers that support it or draws text on canvas with Hershey font -* metrics for non-supporting browsers. -* Removed lots of lint in js code. -* Moved tick css from js code into css file. -* Fix to tick positioning css. y axis ticks were positioned to wrong side of axis div. -* Refactored axis tick renderer instantiation into the axes renderers themselves. - - -For chnages prior to 0.6.0 release, please see change log at http://bitbucket.org/cleonello/jqplot/changesets/ \ No newline at end of file diff --git a/frontend/javascripts/jqplot/copyright.txt b/frontend/javascripts/jqplot/copyright.txt deleted file mode 100644 index c1e969f..0000000 --- a/frontend/javascripts/jqplot/copyright.txt +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2009 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT and GPL version 2.0 licenses. This means that you can - * choose the license that best suits your project and use it accordingly. - * - * Although not required, the author would appreciate an email letting him - * know of any substantial use of jqPlot. You can reach the author at: - * chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . - * - * If you are feeling kind and generous, consider supporting the project by - * making a donation at: http://www.jqplot.com/donate.php . - */ diff --git a/frontend/javascripts/jqplot/excanvas.js b/frontend/javascripts/jqplot/excanvas.js deleted file mode 100644 index 5165fb9..0000000 --- a/frontend/javascripts/jqplot/excanvas.js +++ /dev/null @@ -1,1415 +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; - - /** - * 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 addNamespacesAndStylesheet(doc) { - // create xmlns - if (!doc.namespaces['g_vml_']) { - doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml', - '#default#VML'); - - } - if (!doc.namespaces['g_o_']) { - doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office', - '#default#VML'); - } - - // 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) { - if (/MSIE/.test(navigator.userAgent) && !window.opera) { - 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. - el.firstChild.style.width = el.clientWidth + 'px'; - break; - case 'height': - el.getContext().clearRect(); - el.style.height = el.attributes.height.nodeValue + 'px'; - 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.substr(3, 1) == 'a') { - alpha = Number(parts[3]); - } else { - 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 = 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; - } - - function processStyle(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 = Number(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 {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 = canvasFontSize * (4/3) * fontSize; - } 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; - } - - function processLineCap(lineCap) { - switch (lineCap) { - case 'butt': - return 'flat'; - case 'round': - return 'round'; - case 'square': - default: - return 'square'; - } - } - - /** - * This class implements CanvasRenderingContext2D interface as described by - * the WHATWG. - * @param {HTMLElement} surfaceElement The element that the 2D context should - * be associated with - */ - function CanvasRenderingContext2D_(surfaceElement) { - 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 = surfaceElement; - - var el = surfaceElement.ownerDocument.createElement('div'); - el.style.width = surfaceElement.clientWidth + 'px'; - el.style.height = surfaceElement.clientHeight + 'px'; - el.style.overflow = 'hidden'; - el.style.position = 'absolute'; - surfaceElement.appendChild(el); - - 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 = this.getCoords_(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 = this.getCoords_(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 = this.getCoords_(aX, aY); - var cp1 = this.getCoords_(aCP1x, aCP1y); - var cp2 = this.getCoords_(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 = this.getCoords_(aCPx, aCPy); - var p = this.getCoords_(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 (xStart == xEnd && !aClockwise) { - xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something - // that can be represented in binary - } - - var p = this.getCoords_(aX, aY); - var pStart = this.getCoords_(xStart, yStart); - var pEnd = this.getCoords_(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 = this.getCoords_(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 = ctx.getCoords_(x0, y0); - var p1 = ctx.getCoords_(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 = ctx.getCoords_(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'}); - }; - - /** - * @private - */ - contextPrototype.getCoords_ = function(aX, aY) { - var m = this.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 = this.getCoords_(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/frontend/javascripts/jqplot/gpl-2.0.txt b/frontend/javascripts/jqplot/gpl-2.0.txt deleted file mode 100644 index 864c6b8..0000000 --- a/frontend/javascripts/jqplot/gpl-2.0.txt +++ /dev/null @@ -1,280 +0,0 @@ -Title: GPL Version 2 - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. \ No newline at end of file diff --git a/frontend/javascripts/jqplot/jqPlotCssStyling.txt b/frontend/javascripts/jqplot/jqPlotCssStyling.txt deleted file mode 100644 index 041035d..0000000 --- a/frontend/javascripts/jqplot/jqPlotCssStyling.txt +++ /dev/null @@ -1,53 +0,0 @@ -Title: jqPlot CSS Customization - -Much of the styling of jqPlot is done by css. The jqPlot css file is, unremarkably, -jquery.jqplot.css and resides in the same directory as jqPlot itself. - -There exist some styling related javascript properties on the plot objects themselves -(like fontStyle, fontSize, etc.). These can be set with the options object at plot creation. -Generally, setting these options is *NOT* the preferred way to customize the look of the -plot. Use the css file instead. *These options are deprecated and may disappear*. The -exceptions are certain background and color options which control attributes of something -renderered on a canvas. This would be line color, grid background, etc. These must -be set by the options object. For a list of available options, see . - -Objects in the plot that can be customized by css are given a css class like ".jqplot-*". -For example, the plot title will have a ".jqplot-title" class, the axes ".jqplot-axis", etc. - -Currently assigned classes in jqPlot -are as follows: - -.jqplot-target - Styles for the plot target div. These will be cascaded down -to all plot elements according to css rules. - -.jqplot-axis - Styles for all axes - -.jqplot-xaxis - Styles applied to the primary x axis only. - -.jqplot-yaxis - Styles applied to the primary y axis only. - -.jqplot-x2axis, .jqplot-x3axis, ... - Styles applied to the 2nd, 3rd, etc. x axis only. - -.jqplot-y2axis, .jqplot-y3axis, ... - Styles applied to the 2nd, 3rd, etc.y axis only. - -.jqplot-axis-tick - Styles applied to all axis ticks - -.jqplot-xaxis-tick - Styles applied to primary x axis ticks only. - -.jqplot-x2axis-tick - Styles applied to secondary x axis ticks only. - -.jqplot-yaxis-tick - Styles applied to primary y axis ticks only. - -.jqplot-y2axis-tick - Styles applied to secondary y axis ticks only. - -table.jqplot-table-legend - Styles applied to the legend box table. - -.jqplot-title - Styles applied to the title. - -.jqplot-cursor-tooltip - Styles applied to the cursor tooltip - -.jqplot-highlighter-tooltip - Styles applied to the highlighter tooltip. - -div.jqplot-table-legend-swatch - the div element used for the colored swatch on the legend. - -Note that axes will be assigned 2 classes like: class=".jqplot-axis .jqplot-xaxis". \ No newline at end of file diff --git a/frontend/javascripts/jqplot/jqPlotOptions.txt b/frontend/javascripts/jqplot/jqPlotOptions.txt deleted file mode 100644 index d2d1e68..0000000 --- a/frontend/javascripts/jqplot/jqPlotOptions.txt +++ /dev/null @@ -1,276 +0,0 @@ -Title: jqPlot Options - -**This document is out of date. While the options described here should still be -relavent and valid, it has not been updated for many new options. Sorry for -this inconvenience.** - -This document describes the options available to jqPlot. These are set with the -third argument to the $.jqplot('target', data, options) function. Options are -using the following convention: - -{{{ -property: default, // notes -}}} - -This document is not complete! Not all options are shown! Also, Options marked -with ** in the notes are post 0.7.1 additions. They will be available in the next -release. Further information about the options can be found in the online API -documentation. For details on how the options relate to the API documentation, -see the in the optionsTutorial.txt file. - -{{{ -options = -{ - seriesColors: [ "#4bb2c5", "#c5b47f", "#EAA228", "#579575", "#839557", "#958c12", - "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc"], // colors that will - // be assigned to the series. If there are more series than colors, colors - // will wrap around and start at the beginning again. - - stackSeries: false, // if true, will create a stack plot. - // Currently supported by line and bar graphs. - - title: '', // Title for the plot. Can also be specified as an object like: - - title: { - text: '', // title for the plot, - show: true, - }, - - axesDefaults: { - show: false, // wether or not to renderer the axis. Determined automatically. - min: null, // minimum numerical value of the axis. Determined automatically. - max: null, // maximum numverical value of the axis. Determined automatically. - pad: 1.2, // a factor multiplied by the data range on the axis to give the - // axis range so that data points don't fall on the edges of the axis. - ticks: [], // a 1D [val1, val2, ...], or 2D [[val, label], [val, label], ...] - // array of ticks to use. Computed automatically. - numberTicks: undefined, - renderer: $.jqplot.LinearAxisRenderer, // renderer to use to draw the axis, - rendererOptions: {}, // options to pass to the renderer. LinearAxisRenderer - // has no options, - tickOptions: { - mark: 'outside', // Where to put the tick mark on the axis - // 'outside', 'inside' or 'cross', - showMark: true, - showGridline: true, // wether to draw a gridline (across the whole grid) at this tick, - markSize: 4, // length the tick will extend beyond the grid in pixels. For - // 'cross', length will be added above and below the grid boundary, - show: true, // wether to show the tick (mark and label), - showLabel: true, // wether to show the text label at the tick, - formatString: '', // format string to use with the axis tick formatter - } - showTicks: true, // wether or not to show the tick labels, - showTickMarks: true, // wether or not to show the tick marks - }, - - axes: { - xaxis: { - // same options as axesDefaults - }, - yaxis: { - // same options as axesDefaults - }, - x2axis: { - // same options as axesDefaults - }, - y2axis: { - // same options as axesDefaults - } - }, - - seriesDefaults: { - show: true, // wether to render the series. - xaxis: 'xaxis', // either 'xaxis' or 'x2axis'. - yaxis: 'yaxis', // either 'yaxis' or 'y2axis'. - label: '', // label to use in the legend for this line. - color: '', // CSS color spec to use for the line. Determined automatically. - lineWidth: 2.5, // Width of the line in pixels. - shadow: true, // show shadow or not. - shadowAngle: 45, // angle (degrees) of the shadow, clockwise from x axis. - shadowOffset: 1.25, // offset from the line of the shadow. - shadowDepth: 3, // Number of strokes to make when drawing shadow. Each - // stroke offset by shadowOffset from the last. - shadowAlpha: 0.1, // Opacity of the shadow. - showLine: true, // whether to render the line segments or not. - showMarker: true, // render the data point markers or not. - fill: false, // fill under the line, - fillAndStroke: false, // **stroke a line at top of fill area. - fillColor: undefined, // **custom fill color for filled lines (default is line color). - fillAlpha: undefined, // **custom alpha to apply to fillColor. - renderer: $.jqplot.LineRenderer], // renderer used to draw the series. - rendererOptions: {}, // options passed to the renderer. LineRenderer has no options. - markerRenderer: $.jqplot.MarkerRenderer, // renderer to use to draw the data - // point markers. - markerOptions: { - show: true, // wether to show data point markers. - style: 'filledCircle', // circle, diamond, square, filledCircle. - // filledDiamond or filledSquare. - lineWidth: 2, // width of the stroke drawing the marker. - size: 9, // size (diameter, edge length, etc.) of the marker. - color: '#666666' // color of marker, set to color of line by default. - shadow: true, // wether to draw shadow on marker or not. - shadowAngle: 45, // angle of the shadow. Clockwise from x axis. - shadowOffset: 1, // offset from the line of the shadow, - shadowDepth: 3, // Number of strokes to make when drawing shadow. Each stroke - // offset by shadowOffset from the last. - shadowAlpha: 0.07 // Opacity of the shadow - } - }, - - series:[ - {Each series has same options as seriesDefaults}, - {You can override each series individually here} - ], - - legend: { - show: false, - location: 'ne', // compass direction, nw, n, ne, e, se, s, sw, w. - xoffset: 12, // pixel offset of the legend box from the x (or x2) axis. - yoffset: 12, // pixel offset of the legend box from the y (or y2) axis. - }, - - grid: { - drawGridLines: true, // wether to draw lines across the grid or not. - gridLineColor: '#cccccc' // **Color of the grid lines. - background: '#fffdf6', // CSS color spec for background color of grid. - borderColor: '#999999', // CSS color spec for border around grid. - borderWidth: 2.0, // pixel width of border around grid. - shadow: true, // draw a shadow for grid. - shadowAngle: 45, // angle of the shadow. Clockwise from x axis. - shadowOffset: 1.5, // offset from the line of the shadow. - shadowWidth: 3, // width of the stroke for the shadow. - shadowDepth: 3, // Number of strokes to make when drawing shadow. - // Each stroke offset by shadowOffset from the last. - shadowAlpha: 0.07 // Opacity of the shadow - renderer: $.jqplot.CanvasGridRenderer, // renderer to use to draw the grid. - rendererOptions: {} // options to pass to the renderer. Note, the default - // CanvasGridRenderer takes no additional options. - }, - - // Plugin and renderer options. - - // BarRenderer. - // With BarRenderer, you can specify additional options in the rendererOptions object - // on the series or on the seriesDefaults object. Note, some options are respecified - // (like shadowDepth) to override lineRenderer defaults from which BarRenderer inherits. - - seriesDefaults: { - rendererOptions: { - barPadding: 8, // number of pixels between adjacent bars in the same - // group (same category or bin). - barMargin: 10, // number of pixels between adjacent groups of bars. - barDirection: 'vertical', // vertical or horizontal. - barWidth: null, // width of the bars. null to calculate automatically. - shadowOffset: 2, // offset from the bar edge to stroke the shadow. - shadowDepth: 5, // nuber of strokes to make for the shadow. - shadowAlpha: 0.8, // transparency of the shadow. - } - }, - - // Cursor - // Options are passed to the cursor plugin through the "cursor" object at the top - // level of the options object. - - cursor: { - style: 'crosshair', // A CSS spec for the cursor type to change the - // cursor to when over plot. - show: true, - showTooltip: true, // show a tooltip showing cursor position. - followMouse: false, // wether tooltip should follow the mouse or be stationary. - tooltipLocation: 'se', // location of the tooltip either relative to the mouse - // (followMouse=true) or relative to the plot. One of - // the compass directions, n, ne, e, se, etc. - tooltipOffset: 6, // pixel offset of the tooltip from the mouse or the axes. - showTooltipGridPosition: false, // show the grid pixel coordinates of the mouse - // in the tooltip. - showTooltipUnitPosition: true, // show the coordinates in data units of the mouse - // in the tooltip. - tooltipFormatString: '%.4P', // sprintf style format string for tooltip values. - useAxesFormatters: true, // wether to use the same formatter and formatStrings - // as used by the axes, or to use the formatString - // specified on the cursor with sprintf. - tooltipAxesGroups: [], // show only specified axes groups in tooltip. Would specify like: - // [['xaxis', 'yaxis'], ['xaxis', 'y2axis']]. By default, all axes - // combinations with for the series in the plot are shown. - - }, - - // Dragable - // Dragable options are specified with the "dragable" object at the top level - // of the options object. - - dragable: { - color: undefined, // custom color to use for the dragged point and dragged line - // section. default will use a transparent variant of the line color. - constrainTo: 'none', // Constrain dragging motion to an axis: 'x', 'y', or 'none'. - }, - - // Highlighter - // Highlighter options are specified with the "highlighter" object at the top level - // of the options object. - - highlighter: { - lineWidthAdjust: 2.5, // pixels to add to the size line stroking the data point marker - // when showing highlight. Only affects non filled data point markers. - sizeAdjust: 5, // pixels to add to the size of filled markers when drawing highlight. - showTooltip: true, // show a tooltip with data point values. - tooltipLocation: 'nw', // location of tooltip: n, ne, e, se, s, sw, w, nw. - fadeTooltip: true, // use fade effect to show/hide tooltip. - tooltipFadeSpeed: "fast"// slow, def, fast, or a number of milliseconds. - tooltipOffset: 2, // pixel offset of tooltip from the highlight. - tooltipAxes: 'both', // which axis values to display in the tooltip, x, y or both. - tooltipSeparator: ', ' // separator between values in the tooltip. - useAxesFormatters: true // use the same format string and formatters as used in the axes to - // display values in the tooltip. - tooltipFormatString: '%.5P' // sprintf format string for the tooltip. only used if - // useAxesFormatters is false. Will use sprintf formatter with - // this string, not the axes formatters. - }, - - // LogAxisRenderer - // LogAxisRenderer add 2 options to the axes object. These options are specified directly on - // the axes or axesDefaults object. - - axesDefaults: { - base: 10, // the logarithmic base. - tickDistribution: 'even', // 'even' or 'power'. 'even' will produce with even visiual (pixel) - // spacing on the axis. 'power' will produce ticks spaced by - // increasing powers of the log base. - }, - - // PieRenderer - // PieRenderer accepts options from the rendererOptions object of the series or seriesDefaults object. - - seriesDefaults: { - rendererOptions: { - diameter: undefined, // diameter of pie, auto computed by default. - padding: 20, // padding between pie and neighboring legend or plot margin. - sliceMargin: 0, // gap between slices. - fill: true, // render solid (filled) slices. - shadowOffset: 2, // offset of the shadow from the chart. - shadowDepth: 5, // Number of strokes to make when drawing shadow. Each stroke - // offset by shadowOffset from the last. - shadowAlpha: 0.07 // Opacity of the shadow - } - }, - - // Trendline - // Trendline takes options on the trendline object of the series or seriesDefaults object. - - seriesDefaults: { - trendline: { - show: true, // show the trend line - color: '#666666', // CSS color spec for the trend line. - label: '', // label for the trend line. - type: 'linear', // 'linear', 'exponential' or 'exp' - shadow: true, // show the trend line shadow. - lineWidth: 1.5, // width of the trend line. - shadowAngle: 45, // angle of the shadow. Clockwise from x axis. - shadowOffset: 1.5, // offset from the line of the shadow. - shadowDepth: 3, // Number of strokes to make when drawing shadow. - // Each stroke offset by shadowOffset from the last. - shadowAlpha: 0.07 // Opacity of the shadow - } - } -} -}}} \ No newline at end of file diff --git a/frontend/javascripts/jqplot/jquery-1.3.2.min.js b/frontend/javascripts/jqplot/jquery-1.3.2.min.js deleted file mode 100644 index b1ae21d..0000000 --- a/frontend/javascripts/jqplot/jquery-1.3.2.min.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * jQuery JavaScript Library v1.3.2 - * http://jquery.com/ - * - * Copyright (c) 2009 John Resig - * Dual licensed under the MIT and GPL licenses. - * http://docs.jquery.com/License - * - * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) - * Revision: 6246 - */ -(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("
"]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); -/* - * Sizzle CSS Selector Engine - v0.9.3 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/frontend/javascripts/jqplot/jquery.jqplot.js b/frontend/javascripts/jqplot/jquery.jqplot.js deleted file mode 100644 index cda121a..0000000 --- a/frontend/javascripts/jqplot/jquery.jqplot.js +++ /dev/null @@ -1,4677 +0,0 @@ -/** - * Title: jqPlot Charts - * - * Pure JavaScript plotting plugin for jQuery. - * - * About: Version - * - * 0.9.7 - * - * About: Copyright & License - * - * Copyright (c) 2009 Chris Leonello - * jqPlot is currently available for use in all personal or commercial projects - * under both the MIT and GPL version 2.0 licenses. This means that you can - * choose the license that best suits your project and use it accordingly. - * - * See and contained within this distribution for further information. - * - * The author would appreciate an email letting him know of any substantial - * use of jqPlot. You can reach the author at: chris dot leonello at gmail - * dot com or see http://www.jqplot.com/info.php. This is, of course, not required. - * - * If you are feeling kind and generous, consider supporting the project by - * making a donation at: http://www.jqplot.com/donate.php. - * - * - * About: Introduction - * - * jqPlot requires jQuery (tested with 1.3.2 or better). jQuery 1.3.2 is included in the distribution. - * To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and optionally - * the excanvas script for IE support in your web page: - * - * > - * > - * > - * > - * - * jqPlot can be customized by overriding the defaults of any of the objects which make - * up the plot. The general usage of jqplot is: - * - * > chart = $.jqplot('targetElemId', [dataArray,...], {optionsObject}); - * - * The options available to jqplot are detailed in in the jqPlotOptions.txt file. - * - * An actual call to $.jqplot() may look like the - * examples below: - * - * > chart = $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]); - * - * or - * - * > dataArray = [34,12,43,55,77]; - * > chart = $.jqplot('targetElemId', [dataArray, ...], {title:'My Plot', axes:{yaxis:{min:20, max:100}}}); - * - * For more inforrmation, see . - * - * About: Usage - * - * See - * - * About: Available Options - * - * See for a list of options available thorugh the options object (not complete yet!) - * - * About: Options Usage - * - * See - * - * About: Changes - * - * See - * - */ - -(function($) { - // make sure undefined is undefined - var undefined; - - /** - * Class: $.jqplot - * jQuery function called by the user to create a plot. - * - * Parameters: - * target - ID of target element to render the plot into. - * data - an array of data series. - * options - user defined options object. See the individual classes for available options. - * - * Properties: - * config - object to hold configuration information for jqPlot plot object. - * - * attributes: - * enablePlugins - False to disable plugins by default. Plugins must then be explicitly - * enabled in the individual plot options. Default: true. - * This property sets the "show" property of certain plugins to true or false. - * Only plugins that can be immediately active upon loading are affected. This includes - * non-renderer plugins like cursor, dragable, highlighter, and trendline. - * defaultHeight - Default height for plots where no css height specification exists. This - * is a jqplot wide default. - * defaultWidth - Default height for plots where no css height specification exists. This - * is a jqplot wide default. - */ - - $.jqplot = function(target, data, options) { - var _data, _options; - - // check to see if only 2 arguments were specified, what is what. - if (data == null) { - throw "No data specified"; - } - if (data.constructor == Array && data.length == 0 || data[0].constructor != Array) { - throw "Improper Data Array"; - } - if (options == null) { - if (data instanceof Array) { - _data = data; - _options = null; - } - - else if (data.constructor == Object) { - _data = null; - _options = data; - } - } - else { - _data = data; - _options = options; - } - var plot = new jqPlot(); - plot.init(target, _data, _options); - plot.draw(); - return plot; - }; - - $.jqplot.debug = 1; - $.jqplot.config = { - debug:1, - enablePlugins:true, - defaultHeight:300, - defaultWidth:400 - }; - - $.jqplot.enablePlugins = $.jqplot.config.enablePlugins; - - /** - * - * Hooks: jqPlot Pugin Hooks - * - * $.jqplot.preInitHooks - called before initialization. - * $.jqplot.postInitHooks - called after initialization. - * $.jqplot.preParseOptionsHooks - called before user options are parsed. - * $.jqplot.postParseOptionsHooks - called after user options are parsed. - * $.jqplot.preDrawHooks - called before plot draw. - * $.jqplot.postDrawHooks - called after plot draw. - * $.jqplot.preDrawSeriesHooks - called before each series is drawn. - * $.jqplot.postDrawSeriesHooks - called after each series is drawn. - * $.jqplot.preDrawLegendHooks - called before the legend is drawn. - * $.jqplot.addLegendRowHooks - called at the end of legend draw, so plugins - * can add rows to the legend table. - * $.jqplot.preSeriesInitHooks - called before series is initialized. - * $.jqplot.postSeriesInitHooks - called after series is initialized. - * $.jqplot.preParseSeriesOptionsHooks - called before series related options - * are parsed. - * $.jqplot.postParseSeriesOptionsHooks - called after series related options - * are parsed. - * $.jqplot.eventListenerHooks - called at the end of plot drawing, binds - * listeners to the event canvas which lays on top of the grid area. - * $.jqplot.preDrawSeriesShadowHooks - called before series shadows are drawn. - * $.jqplot.postDrawSeriesShadowHooks - called after series shadows are drawn. - * - */ - - $.jqplot.preInitHooks = []; - $.jqplot.postInitHooks = []; - $.jqplot.preParseOptionsHooks = []; - $.jqplot.postParseOptionsHooks = []; - $.jqplot.preDrawHooks = []; - $.jqplot.postDrawHooks = []; - $.jqplot.preDrawSeriesHooks = []; - $.jqplot.postDrawSeriesHooks = []; - $.jqplot.preDrawLegendHooks = []; - $.jqplot.addLegendRowHooks = []; - $.jqplot.preSeriesInitHooks = []; - $.jqplot.postSeriesInitHooks = []; - $.jqplot.preParseSeriesOptionsHooks = []; - $.jqplot.postParseSeriesOptionsHooks = []; - $.jqplot.eventListenerHooks = []; - $.jqplot.preDrawSeriesShadowHooks = []; - $.jqplot.postDrawSeriesShadowHooks = []; - - // A superclass holding some common properties and methods. - $.jqplot.ElemContainer = function() { - this._elem; - this._plotWidth; - this._plotHeight; - this._plotDimensions = {height:null, width:null}; - }; - - $.jqplot.ElemContainer.prototype.getWidth = function() { - if (this._elem) { - return this._elem.outerWidth(true); - } - else { - return null; - } - }; - - $.jqplot.ElemContainer.prototype.getHeight = function() { - if (this._elem) { - return this._elem.outerHeight(true); - } - else { - return null; - } - }; - - $.jqplot.ElemContainer.prototype.getPosition = function() { - if (this._elem) { - return this._elem.position(); - } - else { - return {top:null, left:null, bottom:null, right:null}; - } - }; - - $.jqplot.ElemContainer.prototype.getTop = function() { - return this.getPosition().top; - }; - - $.jqplot.ElemContainer.prototype.getLeft = function() { - return this.getPosition().left; - }; - - $.jqplot.ElemContainer.prototype.getBottom = function() { - return this._elem.css('bottom'); - }; - - $.jqplot.ElemContainer.prototype.getRight = function() { - return this._elem.css('right'); - }; - - - /** - * Class: Axis - * An individual axis object. Cannot be instantiated directly, but created - * by the Plot oject. Axis properties can be set or overriden by the - * options passed in from the user. - * - */ - function Axis(name) { - $.jqplot.ElemContainer.call(this); - // Group: Properties - // - // Axes options are specified within an axes object at the top level of the - // plot options like so: - // > { - // > axes: { - // > xaxis: {min: 5}, - // > yaxis: {min: 2, max: 8, numberTicks:4}, - // > x2axis: {pad: 1.5}, - // > y2axis: {ticks:[22, 44, 66, 88]} - // > } - // > } - // There are 4 axes, 'xaxis', 'yaxis', 'x2axis', 'y2axis'. Any or all of - // which may be specified. - this.name = name; - this._series = []; - // prop: show - // Wether to display the axis on the graph. - this.show = false; - // prop: tickRenderer - // A class of a rendering engine for creating the ticks labels displayed on the plot, - // See <$.jqplot.AxisTickRenderer>. - this.tickRenderer = $.jqplot.AxisTickRenderer; - // prop: tickOptions - // Options that will be passed to the tickRenderer, see <$.jqplot.AxisTickRenderer> options. - this.tickOptions = {}; - // prop: labelRenderer - // A class of a rendering engine for creating an axis label. - this.labelRenderer = $.jqplot.AxisLabelRenderer; - // prop: labelOptions - // Options passed to the label renderer. - this.labelOptions = {}; - // prop: label - // Label for the axis - this.label = null; - // prop: showLabel - // true to show the axis label. - this.showLabel = true; - // prop: min - // minimum value of the axis (in data units, not pixels). - this.min=null; - // prop: max - // maximum value of the axis (in data units, not pixels). - this.max=null; - // prop: autoscale - // Autoscale the axis min and max values to provide sensible tick spacing. - // If axis min or max are set, autoscale will be turned off. - // The numberTicks, tickInterval and pad options do work with - // autoscale, although tickInterval has not been tested yet. - // padMin and padMax do nothing when autoscale is on. - this.autoscale = false; - // prop: pad - // Padding to extend the range above and below the data bounds. - // The data range is multiplied by this factor to determine minimum and maximum axis bounds. - // A value of 0 will be interpreted to mean no padding, and pad will be set to 1.0. - this.pad = 1.2; - // prop: padMax - // Padding to extend the range above data bounds. - // The top of the data range is multiplied by this factor to determine maximum axis bounds. - // A value of 0 will be interpreted to mean no padding, and padMax will be set to 1.0. - this.padMax = null; - // prop: padMin - // Padding to extend the range below data bounds. - // The bottom of the data range is multiplied by this factor to determine minimum axis bounds. - // A value of 0 will be interpreted to mean no padding, and padMin will be set to 1.0. - this.padMin = null; - // prop: ticks - // 1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis. - // If no label is specified, the value is formatted into an appropriate label. - this.ticks = []; - // prop: numberTicks - // Desired number of ticks. Default is to compute automatically. - this.numberTicks; - // prop: tickInterval - // number of units between ticks. Mutually exclusive with numberTicks. - this.tickInterval; - // prop: renderer - // A class of a rendering engine that handles tick generation, - // scaling input data to pixel grid units and drawing the axis element. - this.renderer = $.jqplot.LinearAxisRenderer; - // prop: rendererOptions - // renderer specific options. See <$.jqplot.LinearAxisRenderer> for options. - this.rendererOptions = {}; - // prop: showTicks - // wether to show the ticks (both marks and labels) or not. - this.showTicks = true; - // prop: showTickMarks - // wether to show the tick marks (line crossing grid) or not. - this.showTickMarks = true; - // prop: showMinorTicks - // Wether or not to show minor ticks. This is renderer dependent. - // The default <$.jqplot.LinearAxisRenderer> does not have minor ticks. - this.showMinorTicks = true; - // prop: useSeriesColor - // Use the color of the first series associated with this axis for the - // tick marks and line bordering this axis. - this.useSeriesColor = false; - // prop: borderWidth - // width of line stroked at the border of the axis. Defaults - // to the width of the grid boarder. - this.borderWidth = null; - // prop: borderColor - // color of the border adjacent to the axis. Defaults to grid border color. - this.borderColor = null; - // minimum and maximum values on the axis. - this._dataBounds = {min:null, max:null}; - // pixel position from the top left of the min value and max value on the axis. - this._offsets = {min:null, max:null}; - this._ticks=[]; - this._label = null; - // prop: syncTicks - // true to try and synchronize tick spacing across multiple axes so that ticks and - // grid lines line up. This has an impact on autoscaling algorithm, however. - // In general, autoscaling an individual axis will work better if it does not - // have to sync ticks. - this.syncTicks = null; - // prop: tickSpacing - // Approximate pixel spacing between ticks on graph. Used during autoscaling. - // This number will be an upper bound, actual spacing will be less. - this.tickSpacing = 75; - // Properties to hold the original values for min, max, ticks, tickInterval and numberTicks - // so they can be restored if altered by plugins. - this._min = null; - this._max = null; - this._tickInterval = null; - this._numberTicks = null; - this.__ticks = null; - } - - Axis.prototype = new $.jqplot.ElemContainer(); - Axis.prototype.constructor = Axis; - - Axis.prototype.init = function() { - this.renderer = new this.renderer(); - // set the axis name - this.tickOptions.axis = this.name; - if (this.label == null || this.label == '') { - this.showLabel = false; - } - else { - this.labelOptions.label = this.label; - } - if (this.showLabel == false) { - this.labelOptions.show = false; - } - // set the default padMax, padMin if not specified - // special check, if no padding desired, padding - // should be set to 1.0 - if (this.pad == 0) { - this.pad = 1.0; - } - if (this.padMax == 0) { - this.padMax = 1.0; - } - if (this.padMin == 0) { - this.padMin = 1.0; - } - if (this.padMax == null) { - this.padMax = (this.pad-1)/2 + 1; - } - if (this.padMin == null) { - this.padMin = (this.pad-1)/2 + 1; - } - // now that padMin and padMax are correctly set, reset pad in case user has supplied - // padMin and/or padMax - this.pad = this.padMax + this.padMin - 1; - if (this.min != null || this.max != null) { - this.autoscale = false; - } - // if not set, sync ticks for y axes but not x by default. - if (this.syncTicks == null && this.name.indexOf('y') > -1) { - this.syncTicks = true; - } - else if (this.syncTicks == null){ - this.syncTicks = false; - } - this.renderer.init.call(this, this.rendererOptions); - - }; - - Axis.prototype.draw = function(ctx) { - return this.renderer.draw.call(this, ctx); - - }; - - Axis.prototype.set = function() { - this.renderer.set.call(this); - }; - - Axis.prototype.pack = function(pos, offsets) { - if (this.show) { - this.renderer.pack.call(this, pos, offsets); - } - // these properties should all be available now. - if (this._min == null) { - this._min = this.min; - this._max = this.max; - this._tickInterval = this.tickInterval; - this._numberTicks = this.numberTicks; - this.__ticks = this._ticks; - } - }; - - // reset the axis back to original values if it has been scaled, zoomed, etc. - Axis.prototype.reset = function() { - this.renderer.reset.call(this); - }; - - Axis.prototype.resetScale = function() { - this.min = null; - this.max = null; - this.numberTicks = null; - this.tickInterval = null; - }; - - /** - * Class: Legend - * Legend object. Cannot be instantiated directly, but created - * by the Plot oject. Legend properties can be set or overriden by the - * options passed in from the user. - */ - function Legend(options) { - $.jqplot.ElemContainer.call(this); - // Group: Properties - - // prop: show - // Wether to display the legend on the graph. - this.show = false; - // prop: location - // Placement of the legend. one of the compass directions: nw, n, ne, e, se, s, sw, w - this.location = 'ne'; - // prop: xoffset - // offset from the inside edge of the plot in the x direction in pixels. - this.xoffset = 12; - // prop: yoffset - // offset from the inside edge of the plot in the y direction in pixels. - this.yoffset = 12; - // prop: border - // css spec for the border around the legend box. - this.border; - // prop: background - // css spec for the background of the legend box. - this.background; - // prop: textColor - // css color spec for the legend text. - this.textColor; - // prop: fontFamily - // css font-family spec for the legend text. - this.fontFamily; - // prop: fontSize - // css font-size spec for the legend text. - this.fontSize ; - // prop: rowSpacing - // css padding-top spec for the rows in the legend. - this.rowSpacing = '0.5em'; - // renderer - // A class that will create a DOM object for the legend, - // see <$.jqplot.TableLegendRenderer>. - this.renderer = $.jqplot.TableLegendRenderer; - // prop: rendererOptions - // renderer specific options passed to the renderer. - this.rendererOptions = {}; - // prop: predraw - // Wether to draw the legend before the series or not. - this.preDraw = false; - this.escapeHtml = false; - this._series = []; - - $.extend(true, this, options); - } - - Legend.prototype = new $.jqplot.ElemContainer(); - Legend.prototype.constructor = Legend; - - Legend.prototype.init = function() { - this.renderer = new this.renderer(); - this.renderer.init.call(this, this.rendererOptions); - }; - - Legend.prototype.draw = function(offsets) { - for (var i=0; i<$.jqplot.preDrawLegendHooks.length; i++){ - $.jqplot.preDrawLegendHooks[i].call(this, offsets); - } - return this.renderer.draw.call(this, offsets); - }; - - Legend.prototype.pack = function(offsets) { - this.renderer.pack.call(this, offsets); - }; - - /** - * Class: Title - * Plot Title object. Cannot be instantiated directly, but created - * by the Plot oject. Title properties can be set or overriden by the - * options passed in from the user. - * - * Parameters: - * text - text of the title. - */ - function Title(text) { - $.jqplot.ElemContainer.call(this); - // Group: Properties - - // prop: text - // text of the title; - this.text = text; - // prop: show - // wether or not to show the title - this.show = true; - // prop: fontFamily - // css font-family spec for the text. - this.fontFamily; - // prop: fontSize - // css font-size spec for the text. - this.fontSize ; - // prop: textAlign - // css text-align spec for the text. - this.textAlign; - // prop: textColor - // css color spec for the text. - this.textColor; - // prop: renderer - // A class for creating a DOM element for the title, - // see <$.jqplot.DivTitleRenderer>. - this.renderer = $.jqplot.DivTitleRenderer; - // prop: rendererOptions - // renderer specific options passed to the renderer. - this.rendererOptions = {}; - } - - Title.prototype = new $.jqplot.ElemContainer(); - Title.prototype.constructor = Title; - - Title.prototype.init = function() { - this.renderer = new this.renderer(); - this.renderer.init.call(this, this.rendererOptions); - }; - - Title.prototype.draw = function(width) { - return this.renderer.draw.call(this, width); - }; - - Title.prototype.pack = function() { - this.renderer.pack.call(this); - }; - - - /** - * Class: Series - * An individual data series object. Cannot be instantiated directly, but created - * by the Plot oject. Series properties can be set or overriden by the - * options passed in from the user. - */ - function Series() { - $.jqplot.ElemContainer.call(this); - // Group: Properties - // Properties will be assigned from a series array at the top level of the - // options. If you had two series and wanted to change the color and line - // width of the first and set the second to use the secondary y axis with - // no shadow and supply custom labels for each: - // > { - // > series:[ - // > {color: '#ff4466', lineWidth: 5, label:'good line'}, - // > {yaxis: 'y2axis', shadow: false, label:'bad line'} - // > ] - // > } - - // prop: show - // wether or not to draw the series. - this.show = true; - // prop: xaxis - // which x axis to use with this series, either 'xaxis' or 'x2axis'. - this.xaxis = 'xaxis'; - this._xaxis; - // prop: yaxis - // which y axis to use with this series, either 'yaxis' or 'y2axis'. - this.yaxis = 'yaxis'; - this._yaxis; - this.gridBorderWidth = 2.0; - // prop: renderer - // A class of a renderer which will draw the series, - // see <$.jqplot.LineRenderer>. - this.renderer = $.jqplot.LineRenderer; - // prop: rendererOptions - // Options to pass on to the renderer. - this.rendererOptions = {}; - this.data = []; - this.gridData = []; - // prop: label - // Line label to use in the legend. - this.label = ''; - // prop: showLabel - // true to show label for this series in the legend. - this.showLabel = true; - // prop: color - // css color spec for the series - this.color; - // prop: lineWidth - // width of the line in pixels. May have different meanings depending on renderer. - this.lineWidth = 2.5; - // prop: shadow - // wether or not to draw a shadow on the line - this.shadow = true; - // prop: shadowAngle - // Shadow angle in degrees - this.shadowAngle = 45; - // prop: shadowOffset - // Shadow offset from line in pixels - this.shadowOffset = 1.25; - // prop: shadowDepth - // Number of times shadow is stroked, each stroke offset shadowOffset from the last. - this.shadowDepth = 3; - // prop: shadowAlpha - // Alpha channel transparency of shadow. 0 = transparent. - this.shadowAlpha = '0.1'; - // prop: breakOnNull - // Not implemented. wether line segments should be be broken at null value. - // False will join point on either side of line. - this.breakOnNull = false; - // prop: markerRenderer - // A class of a renderer which will draw marker (e.g. circle, square, ...) at the data points, - // see <$.jqplot.MarkerRenderer>. - this.markerRenderer = $.jqplot.MarkerRenderer; - // prop: markerOptions - // renderer specific options to pass to the markerRenderer, - // see <$.jqplot.MarkerRenderer>. - this.markerOptions = {}; - // prop: showLine - // wether to actually draw the line or not. Series will still be renderered, even if no line is drawn. - this.showLine = true; - // prop: showMarker - // wether or not to show the markers at the data points. - this.showMarker = true; - // prop: index - // 0 based index of this series in the plot series array. - this.index; - // prop: fill - // true or false, wether to fill under lines or in bars. - // May not be implemented in all renderers. - this.fill = false; - // prop: fillColor - // CSS color spec to use for fill under line. Defaults to line color. - this.fillColor; - // prop: fillAlpha - // Alpha transparency to apply to the fill under the line. - // Use this to adjust alpha separate from fill color. - this.fillAlpha; - // prop: fillAndStroke - // If true will stroke the line (with color this.color) as well as fill under it. - // Applies only when fill is true. - this.fillAndStroke = false; - // prop: disableStack - // true to not stack this series with other series in the plot. - // To render properly, non-stacked series must come after any stacked series - // in the plot's data series array. So, the plot's data series array would look like: - // > [stackedSeries1, stackedSeries2, ..., nonStackedSeries1, nonStackedSeries2, ...] - // disableStack will put a gap in the stacking order of series, and subsequent - // stacked series will not fill down through the non-stacked series and will - // most likely not stack properly on top of the non-stacked series. - this.disableStack = false; - // _stack is set by the Plot if the plot is a stacked chart. - // will stack lines or bars on top of one another to build a "mountain" style chart. - // May not be implemented in all renderers. - this._stack = false; - // prop: neighborThreshold - // how close or far (in pixels) the cursor must be from a point marker to detect the point. - this.neighborThreshold = 4; - // prop: fillToZero - // true will force bar and filled series to fill toward zero on the fill Axis. - this.fillToZero = false; - // prop: fillAxis - // Either 'x' or 'y'. Which axis to fill the line toward if fillToZero is true. - // 'y' means fill up/down to 0 on the y axis for this series. - this.fillAxis = 'y'; - // prop: useNegativeColors - // true to color negative values differently in filled and bar charts. - this.useNegativeColors = true; - this._stackData = []; - // _plotData accounts for stacking. If plots not stacked, _plotData and data are same. If - // stacked, _plotData is accumulation of stacking data. - this._plotData = []; - // _plotValues hold the individual x and y values that will be plotted for this series. - this._plotValues = {x:[], y:[]}; - // statistics about the intervals between data points. Used for auto scaling. - this._intervals = {x:{}, y:{}}; - // data from the previous series, for stacked charts. - this._prevPlotData = []; - this._prevGridData = []; - this._stackAxis = 'y'; - this._primaryAxis = '_xaxis'; - // give each series a canvas to draw on. This should allow for redrawing speedups. - this.canvas = new $.jqplot.GenericCanvas(); - this.shadowCanvas = new $.jqplot.GenericCanvas(); - this.plugins = {}; - // sum of y values in this series. - this._sumy = 0; - this._sumx = 0; - } - - Series.prototype = new $.jqplot.ElemContainer(); - Series.prototype.constructor = Series; - - Series.prototype.init = function(index, gridbw, plot) { - // weed out any null values in the data. - this.index = index; - this.gridBorderWidth = gridbw; - var d = this.data; - for (var i=0; i. - this.renderer = $.jqplot.CanvasGridRenderer; - // prop: rendererOptions - // Options to pass on to the renderer, - // see <$.jqplot.CanvasGridRenderer>. - this.rendererOptions = {}; - this._offsets = {top:null, bottom:null, left:null, right:null}; - } - - Grid.prototype = new $.jqplot.ElemContainer(); - Grid.prototype.constructor = Grid; - - Grid.prototype.init = function() { - this.renderer = new this.renderer(); - this.renderer.init.call(this, this.rendererOptions); - }; - - Grid.prototype.createElement = function(offsets) { - this._offsets = offsets; - return this.renderer.createElement.call(this); - }; - - Grid.prototype.draw = function() { - this.renderer.draw.call(this); - }; - - $.jqplot.GenericCanvas = function() { - $.jqplot.ElemContainer.call(this); - this._ctx; - }; - - $.jqplot.GenericCanvas.prototype = new $.jqplot.ElemContainer(); - $.jqplot.GenericCanvas.prototype.constructor = $.jqplot.GenericCanvas; - - $.jqplot.GenericCanvas.prototype.createElement = function(offsets, clss, plotDimensions) { - this._offsets = offsets; - var klass = 'jqplot'; - if (clss != undefined) { - klass = clss; - } - var elem = document.createElement('canvas'); - // if new plotDimensions supplied, use them. - if (plotDimensions != undefined) { - this._plotDimensions = plotDimensions; - } - elem.width = this._plotDimensions.width - this._offsets.left - this._offsets.right; - elem.height = this._plotDimensions.height - this._offsets.top - this._offsets.bottom; - this._elem = $(elem); - this._elem.addClass(klass); - this._elem.css({ position: 'absolute', left: this._offsets.left, top: this._offsets.top }); - // borrowed from flot by Ole Laursen - if ($.browser.msie) { - window.G_vmlCanvasManager.init_(document); - } - if ($.browser.msie) { - elem = window.G_vmlCanvasManager.initElement(elem); - } - return this._elem; - }; - - $.jqplot.GenericCanvas.prototype.setContext = function() { - this._ctx = this._elem.get(0).getContext("2d"); - return this._ctx; - }; - - /** - * Class: jqPlot - * Plot object returned by call to $.jqplot. Handles parsing user options, - * creating sub objects (Axes, legend, title, series) and rendering the plot. - */ - function jqPlot() { - // Group: Properties - // These properties are specified at the top of the options object - // like so: - // > { - // > axesDefaults:{min:0}, - // > series:[{color:'#6633dd'}], - // > title: 'A Plot' - // > } - // - // prop: data - // user's data. Data should *NOT* be specified in the options object, - // but be passed in as the second argument to the $.jqplot() function. - // The data property is described here soley for reference. - // The data should be in the form of an array of 2D or 1D arrays like - // > [ [[x1, y1], [x2, y2],...], [y1, y2, ...] ]. - this.data = []; - // The id of the dom element to render the plot into - this.targetId = null; - // the jquery object for the dom target. - this.target = null; - this.defaults = { - // prop: axesDefaults - // default options that will be applied to all axes. - // see for axes options. - axesDefaults: {}, - axes: {xaxis:{}, yaxis:{}, x2axis:{}, y2axis:{}, y3axis:{}, y4axis:{}, y5axis:{}, y6axis:{}, y7axis:{}, y8axis:{}, y9axis:{}}, - // prop: seriesDefaults - // default options that will be applied to all series. - // see for series options. - seriesDefaults: {}, - gridPadding: {top:10, right:10, bottom:23, left:10}, - series:[] - }; - // prop: series - // Array of series object options. - // see for series specific options. - this.series = []; - // prop: axes - // up to 4 axes are supported, each with it's own options, - // See for axis specific options. - this.axes = {xaxis: new Axis('xaxis'), yaxis: new Axis('yaxis'), x2axis: new Axis('x2axis'), y2axis: new Axis('y2axis'), y3axis: new Axis('y3axis'), y4axis: new Axis('y4axis'), y5axis: new Axis('y5axis'), y6axis: new Axis('y6axis'), y7axis: new Axis('y7axis'), y8axis: new Axis('y8axis'), y9axis: new Axis('y9axis')}; - // prop: grid - // See for grid specific options. - this.grid = new Grid(); - // prop: legend - // see <$.jqplot.TableLegendRenderer> - this.legend = new Legend(); - this.baseCanvas = new $.jqplot.GenericCanvas(); - // this.seriesCanvas = new $.jqplot.GenericCanvas(); - this.eventCanvas = new $.jqplot.GenericCanvas(); - this._width = null; - this._height = null; - this._plotDimensions = {height:null, width:null}; - this._gridPadding = {top:10, right:10, bottom:10, left:10}; - // a shortcut for axis syncTicks options. Not implemented yet. - this.syncXTicks = true; - // a shortcut for axis syncTicks options. Not implemented yet. - this.syncYTicks = true; - // prop: seriesColors - // Ann array of CSS color specifications that will be applied, in order, - // to the series in the plot. Colors will wrap around so, if their - // are more series than colors, colors will be reused starting at the - // beginning. For pie charts, this specifies the colors of the slices. - this.seriesColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"]; - this.negativeSeriesColors = [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"]; - // prop: sortData - // false to not sort the data passed in by the user. - // Many bar, stakced and other graphs as well as many plugins depend on - // having sorted data. - this.sortData = true; - var seriesColorsIndex = 0; - // prop textColor - // css spec for the css color attribute. Default for the entire plot. - this.textColor; - // prop; fontFamily - // css spec for the font-family attribute. Default for the entire plot. - this.fontFamily; - // prop: fontSize - // css spec for the font-size attribute. Default for the entire plot. - this.fontSize; - // prop: title - // Title object. See for specific options. As a shortcut, you - // can specify the title option as just a string like: title: 'My Plot' - // and this will create a new title object with the specified text. - this.title = new Title(); - // container to hold all of the merged options. Convienence for plugins. - this.options = {}; - // prop: stackSeries - // true or false, creates a stack or "mountain" plot. - // Not all series renderers may implement this option. - this.stackSeries = false; - // array to hold the cumulative stacked series data. - // used to ajust the individual series data, which won't have access to other - // series data. - this._stackData = []; - // array that holds the data to be plotted. This will be the series data - // merged with the the appropriate data from _stackData according to the stackAxis. - this._plotData = []; - // Namespece to hold plugins. Generally non-renderer plugins add themselves to here. - this.plugins = {}; - // Count how many times the draw method has been called while the plot is visible. - // Mostly used to test if plot has never been dran (=0), has been successfully drawn - // into a visible container once (=1) or draw more than once into a visible container. - // Can use this in tests to see if plot has been visibly drawn at least one time. - // After plot has been visibly drawn once, it generally doesn't need redrawn if its - // container is hidden and shown. - this._drawCount = 0; - // prop: drawIfHidden - // True to execute the draw method even if the plot target is hidden. - // Generally, this should be false. Most plot elements will not be sized/ - // positioned correclty if renderered into a hidden container. To render into - // a hidden container, call the replot method when the container is shown. - this.drawIfHidden = false; - // sum of y values for all series in plot. - // used in mekko chart. - this._sumy = 0; - this._sumx = 0; - - this.colorGenerator = $.jqplot.ColorGenerator; - - // Group: methods - // - // method: init - // sets the plot target, checks data and applies user - // options to plot. - this.init = function(target, data, options) { - for (var i=0; i<$.jqplot.preInitHooks.length; i++) { - $.jqplot.preInitHooks[i].call(this, target, data, options); - } - this.targetId = '#'+target; - this.target = $('#'+target); - if (!this.target.get(0)) { - throw "No plot target specified"; - } - - // make sure the target is positioned by some means and set css - if (this.target.css('position') == 'static') { - this.target.css('position', 'relative'); - } - if (!this.target.hasClass('jqplot-target')) { - this.target.addClass('jqplot-target'); - } - - // if no height or width specified, use a default. - if (!this.target.height()) { - var h; - if (options && options.height) { - h = parseInt(options.height, 10); - } - else if (this.target.attr('data-height')) { - h = parseInt(this.target.attr('data-height'), 10); - } - else { - h = parseInt($.jqplot.config.defaultHeight, 10); - } - this._height = h; - this.target.css('height', h+'px'); - } - else { - this._height = this.target.height(); - } - if (!this.target.width()) { - var w; - if (options && options.width) { - w = parseInt(options.width, 10); - } - else if (this.target.attr('data-width')) { - w = parseInt(this.target.attr('data-width'), 10); - } - else { - w = parseInt($.jqplot.config.defaultWidth, 10); - } - this._width = w; - this.target.css('width', w+'px'); - } - else { - this._width = this.target.width(); - } - - this._plotDimensions.height = this._height; - this._plotDimensions.width = this._width; - this.grid._plotDimensions = this._plotDimensions; - this.title._plotDimensions = this._plotDimensions; - this.baseCanvas._plotDimensions = this._plotDimensions; - this.eventCanvas._plotDimensions = this._plotDimensions; - this.legend._plotDimensions = this._plotDimensions; - if (this._height <=0 || this._width <=0 || !this._height || !this._width) { - throw "Canvas dimension not set"; - } - - this.data = data; - - this.parseOptions(options); - - if (this.textColor) { - this.target.css('color', this.textColor); - } - if (this.fontFamily) { - this.target.css('font-family', this.fontFamily); - } - if (this.fontSize) { - this.target.css('font-size', this.fontSize); - } - - this.title.init(); - this.legend.init(); - this._sumy = 0; - this._sumx = 0; - for (var i=0; i<this.series.length; i++) { - this.series[i].shadowCanvas._plotDimensions = this._plotDimensions; - this.series[i].canvas._plotDimensions = this._plotDimensions; - for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) { - $.jqplot.preSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i]); - } - this.populatePlotData(this.series[i], i); - this.series[i]._plotDimensions = this._plotDimensions; - this.series[i].init(i, this.grid.borderWidth, this); - for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) { - $.jqplot.postSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i]); - } - this._sumy += this.series[i]._sumy; - this._sumx += this.series[i]._sumx; - } - - for (var name in this.axes) { - this.axes[name]._plotDimensions = this._plotDimensions; - this.axes[name].init(); - } - - if (this.sortData) { - sortData(this.series); - } - this.grid.init(); - this.grid._axes = this.axes; - - this.legend._series = this.series; - - for (var i=0; i<$.jqplot.postInitHooks.length; i++) { - $.jqplot.postInitHooks[i].call(this, target, data, options); - } - }; - - // method: resetAxesScale - // Reset the specified axes min, max, numberTicks and tickInterval properties to null - // or reset these properties on all axes if no list of axes is provided. - // - // Parameters: - // axes - Boolean to reset or not reset all axes or an array or object of axis names to reset. - this.resetAxesScale = function(axes) { - var ax = (axes != undefined) ? axes : this.axes; - if (ax === true) { - ax = this.axes; - } - if (ax.constructor === Array) { - for (var i = 0; i < ax.length; i++) { - this.axes[ax[i]].resetScale(); - } - } - else if (ax.constructor === Object) { - for (var name in ax) { - this.axes[name].resetScale(); - } - } - }; - // method: reInitialize - // reinitialize plot for replotting. - // not called directly. - this.reInitialize = function () { - // Plot should be visible and have a height and width. - // If plot doesn't have height and width for some - // reason, set it by other means. Plot must not have - // a display:none attribute, however. - if (!this.target.height()) { - var h; - if (options && options.height) { - h = parseInt(options.height, 10); - } - else if (this.target.attr('data-height')) { - h = parseInt(this.target.attr('data-height'), 10); - } - else { - h = parseInt($.jqplot.config.defaultHeight, 10); - } - this._height = h; - this.target.css('height', h+'px'); - } - else { - this._height = this.target.height(); - } - if (!this.target.width()) { - var w; - if (options && options.width) { - w = parseInt(options.width, 10); - } - else if (this.target.attr('data-width')) { - w = parseInt(this.target.attr('data-width'), 10); - } - else { - w = parseInt($.jqplot.config.defaultWidth, 10); - } - this._width = w; - this.target.css('width', w+'px'); - } - else { - this._width = this.target.width(); - } - - if (this._height <=0 || this._width <=0 || !this._height || !this._width) { - throw "Target dimension not set"; - } - - this._plotDimensions.height = this._height; - this._plotDimensions.width = this._width; - this.grid._plotDimensions = this._plotDimensions; - this.title._plotDimensions = this._plotDimensions; - this.baseCanvas._plotDimensions = this._plotDimensions; - // this.seriesCanvas._plotDimensions = this._plotDimensions; - this.eventCanvas._plotDimensions = this._plotDimensions; - this.legend._plotDimensions = this._plotDimensions; - - for (var n in this.axes) { - var axis = this.axes[n]; - axis._plotWidth = this._width; - axis._plotHeight = this._height; - } - - this.title._plotWidth = this._width; - - if (this.textColor) { - this.target.css('color', this.textColor); - } - if (this.fontFamily) { - this.target.css('font-family', this.fontFamily); - } - if (this.fontSize) { - this.target.css('font-size', this.fontSize); - } - - this._sumy = 0; - this._sumx = 0; - for (var i=0; i<this.series.length; i++) { - this.populatePlotData(this.series[i], i); - this.series[i]._plotDimensions = this._plotDimensions; - this.series[i].canvas._plotDimensions = this._plotDimensions; - //this.series[i].init(i, this.grid.borderWidth); - this._sumy += this.series[i]._sumy; - this._sumx += this.series[i]._sumx; - } - - for (var name in this.axes) { - this.axes[name]._plotDimensions = this._plotDimensions; - this.axes[name]._ticks = []; - this.axes[name].renderer.init.call(this.axes[name], {}); - } - - if (this.sortData) { - sortData(this.series); - } - - this.grid._axes = this.axes; - - this.legend._series = this.series; - }; - - // sort the series data in increasing order. - function sortData(series) { - var d, ret; - for (var i=0; i<series.length; i++) { - d = series[i].data; - var check = true; - if (series[i]._stackAxis == 'x') { - for (var j = 0; j < d.length; j++) { - if (typeof(d[j][1]) != "number") { - check = false; - break; - } - } - if (check) { - d.sort(function(a,b) { return a[1] - b[1]; }); - } - } - else { - for (var j = 0; j < d.length; j++) { - if (typeof(d[j][0]) != "number") { - check = false; - break; - } - } - if (check) { - d.sort(function(a,b) { return a[0] - b[0]; }); - } - } - } - } - - // populate the _stackData and _plotData arrays for the plot and the series. - this.populatePlotData = function(series, index) { - // if a stacked chart, compute the stacked data - this._plotData = []; - this._stackData = []; - series._stackData = []; - series._plotData = []; - var plotValues = {x:[], y:[]}; - if (this.stackSeries && !series.disableStack) { - series._stack = true; - var sidx = series._stackAxis == 'x' ? 0 : 1; - var idx = sidx ? 0 : 1; - // push the current data into stackData - //this._stackData.push(this.series[i].data); - var temp = $.extend(true, [], series.data); - // create the data that will be plotted for this series - var plotdata = $.extend(true, [], series.data); - // for first series, nothing to add to stackData. - for (var j=0; j<index; j++) { - var cd = this.series[j].data; - for (var k=0; k<cd.length; k++) { - temp[k][0] += cd[k][0]; - temp[k][1] += cd[k][1]; - // only need to sum up the stack axis column of data - plotdata[k][sidx] += cd[k][sidx]; - } - } - for (var i=0; i<plotdata.length; i++) { - plotValues.x.push(plotdata[i][0]); - plotValues.y.push(plotdata[i][1]); - } - this._plotData.push(plotdata); - this._stackData.push(temp); - series._stackData = temp; - series._plotData = plotdata; - series._plotValues = plotValues; - } - else { - for (var i=0; i<series.data.length; i++) { - plotValues.x.push(series.data[i][0]); - plotValues.y.push(series.data[i][1]); - } - this._stackData.push(series.data); - this.series[index]._stackData = series.data; - this._plotData.push(series.data); - series._plotData = series.data; - series._plotValues = plotValues; - } - if (index>0) { - series._prevPlotData = this.series[index-1]._plotData; - } - series._sumy = 0; - series._sumx = 0; - for (i=series.data.length-1; i>-1; i--) { - series._sumy += series.data[i][1]; - series._sumx += series.data[i][0]; - } - }; - - // function to safely return colors from the color array and wrap around at the end. - this.getNextSeriesColor = (function(t) { - var idx = 0; - var sc = t.seriesColors; - - return function () { - if (idx < sc.length) { - return sc[idx++]; - } - else { - idx = 0; - return sc[idx++]; - } - }; - })(this); - - this.parseOptions = function(options){ - for (var i=0; i<$.jqplot.preParseOptionsHooks.length; i++) { - $.jqplot.preParseOptionsHooks[i].call(this, options); - } - this.options = $.extend(true, {}, this.defaults, options); - this.stackSeries = this.options.stackSeries; - if (this.options.seriesColors) { - this.seriesColors = this.options.seriesColors; - } - var cg = new this.colorGenerator(this.seriesColors); - // this._gridPadding = this.options.gridPadding; - $.extend(true, this._gridPadding, this.options.gridPadding); - this.sortData = (this.options.sortData != null) ? this.options.sortData : this.sortData; - for (var n in this.axes) { - var axis = this.axes[n]; - $.extend(true, axis, this.options.axesDefaults, this.options.axes[n]); - axis._plotWidth = this._width; - axis._plotHeight = this._height; - } - if (this.data.length == 0) { - this.data = []; - for (var i=0; i<this.options.series.length; i++) { - this.data.push(this.options.series.data); - } - } - - var normalizeData = function(data, dir) { - // return data as an array of point arrays, - // in form [[x1,y1...], [x2,y2...], ...] - var temp = []; - var i; - dir = dir || 'vertical'; - if (!(data[0] instanceof Array)) { - // we have a series of scalars. One line with just y values. - // turn the scalar list of data into a data array of form: - // [[1, data[0]], [2, data[1]], ...] - for (var i=0; i<data.length; i++) { - if (dir == 'vertical') { - temp.push([i+1, data[i]]); - } - else { - temp.push([data[i], i+1]); - } - } - } - else { - // we have a properly formatted data series, copy it. - $.extend(true, temp, data); - } - return temp; - }; - - for (var i=0; i<this.data.length; i++) { - var temp = new Series(); - for (var j=0; j<$.jqplot.preParseSeriesOptionsHooks.length; j++) { - $.jqplot.preParseSeriesOptionsHooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]); - } - $.extend(true, temp, {seriesColors:this.seriesColors, negativeSeriesColors:this.negativeSeriesColors}, this.options.seriesDefaults, this.options.series[i]); - var dir = 'vertical'; - if (temp.renderer.constructor == $.jqplot.barRenderer && temp.rendererOptions && temp.rendererOptions.barDirection == 'horizontal') { - dir = 'horizontal'; - } - temp.data = normalizeData(this.data[i], dir); - switch (temp.xaxis) { - case 'xaxis': - temp._xaxis = this.axes.xaxis; - break; - case 'x2axis': - temp._xaxis = this.axes.x2axis; - break; - default: - break; - } - temp._yaxis = this.axes[temp.yaxis]; - temp._xaxis._series.push(temp); - temp._yaxis._series.push(temp); - if (temp.show) { - temp._xaxis.show = true; - temp._yaxis.show = true; - } - - // parse the renderer options and apply default colors if not provided - if (!temp.color && temp.show != false) { - temp.color = cg.next(); - } - if (!temp.label) { - temp.label = 'Series '+ (i+1).toString(); - } - // temp.rendererOptions.show = temp.show; - // $.extend(true, temp.renderer, {color:this.seriesColors[i]}, this.rendererOptions); - this.series.push(temp); - for (var j=0; j<$.jqplot.postParseSeriesOptionsHooks.length; j++) { - $.jqplot.postParseSeriesOptionsHooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]); - } - } - - // copy the grid and title options into this object. - $.extend(true, this.grid, this.options.grid); - // if axis border properties aren't set, set default. - for (var n in this.axes) { - var axis = this.axes[n]; - if (axis.borderWidth == null) { - axis.borderWidth =this.grid.borderWidth; - } - if (axis.borderColor == null) { - if (n != 'xaxis' && n != 'x2axis' && axis.useSeriesColor === true && axis.show) { - axis.borderColor = axis._series[0].color; - } - else { - axis.borderColor = this.grid.borderColor; - } - } - } - - if (typeof this.options.title == 'string') { - this.title.text = this.options.title; - } - else if (typeof this.options.title == 'object') { - $.extend(true, this.title, this.options.title); - } - this.title._plotWidth = this._width; - $.extend(true, this.legend, this.options.legend); - - for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) { - $.jqplot.postParseOptionsHooks[i].call(this, options); - } - }; - - // method: replot - // Does a reinitialization of the plot followed by - // a redraw. Method could be used to interactively - // change plot characteristics and then replot. - // - // Parameters: - // options - Options used for replotting. - // - // Properties: - // clear - false to not clear (empty) the plot container before replotting (default: true). - // resetAxes - true to reset all axes min, max, numberTicks and tickInterval setting so axes will rescale themselves. - // optionally pass in list of axes to reset (e.g. ['xaxis', 'y2axis']) (default: false). - this.replot = function(options) { - var opts = (options != undefined) ? options : {}; - var clear = (opts.clear != undefined) ? opts.clear : true; - var resetAxes = (opts.resetAxes != undefined) ? opts.resetAxes : false; - this.target.trigger('jqplotPreReplot'); - if (clear) { - this.target.empty(); - } - if (resetAxes) { - this.resetAxesScale(resetAxes); - } - this.reInitialize(); - this.draw(); - this.target.trigger('jqplotPostReplot'); - }; - - // method: redraw - // Empties the plot target div and redraws the plot. - // This enables plot data and properties to be changed - // and then to comletely clear the plot and redraw. - // redraw *will not* reinitialize any plot elements. - // That is, axes will not be autoscaled and defaults - // will not be reapplied to any plot elements. redraw - // is used primarily with zooming. - // - // Parameters: - // clear - false to not clear (empty) the plot container before redrawing (default: true). - this.redraw = function(clear) { - clear = (clear != null) ? clear : true; - this.target.trigger('jqplotPreRedraw'); - if (clear) { - this.target.empty(); - } - for (var ax in this.axes) { - this.axes[ax]._ticks = []; - } - for (var i=0; i<this.series.length; i++) { - this.populatePlotData(this.series[i], i); - } - this._sumy = 0; - this._sumx = 0; - for (i=0; i<this.series.length; i++) { - this._sumy += this.series[i]._sumy; - this._sumx += this.series[i]._sumx; - } - this.draw(); - this.target.trigger('jqplotPostRedraw'); - }; - - // method: draw - // Draws all elements of the plot into the container. - // Does not clear the container before drawing. - this.draw = function(){ - if (this.drawIfHidden || this.target.is(':visible')) { - this.target.trigger('jqplotPreDraw'); - var i; - for (i=0; i<$.jqplot.preDrawHooks.length; i++) { - $.jqplot.preDrawHooks[i].call(this); - } - // create an underlying canvas to be used for special features. - this.target.append(this.baseCanvas.createElement({left:0, right:0, top:0, bottom:0}, 'jqplot-base-canvas')); - var bctx = this.baseCanvas.setContext(); - this.target.append(this.title.draw()); - this.title.pack({top:0, left:0}); - for (var name in this.axes) { - this.target.append(this.axes[name].draw(bctx)); - this.axes[name].set(); - } - if (this.axes.yaxis.show) { - this._gridPadding.left = this.axes.yaxis.getWidth(); - } - var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; - var rapad = [0, 0, 0, 0]; - var gpr = 0; - var n, ax; - for (n=8; n>0; n--) { - ax = this.axes[ra[n-1]]; - if (ax.show) { - rapad[n-1] = gpr; - gpr += ax.getWidth(); - } - } - if (gpr > this._gridPadding.right) { - this._gridPadding.right = gpr; - } - if (this.title.show && this.axes.x2axis.show) { - this._gridPadding.top = this.title.getHeight() + this.axes.x2axis.getHeight(); - } - else if (this.title.show) { - this._gridPadding.top = this.title.getHeight(); - } - else if (this.axes.x2axis.show) { - this._gridPadding.top = this.axes.x2axis.getHeight(); - } - if (this.axes.xaxis.show) { - this._gridPadding.bottom = this.axes.xaxis.getHeight(); - } - - this.axes.xaxis.pack({position:'absolute', bottom:0, left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right}); - this.axes.yaxis.pack({position:'absolute', top:0, left:0, height:this._height}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); - this.axes.x2axis.pack({position:'absolute', top:this.title.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right}); - for (i=8; i>0; i--) { - this.axes[ra[i-1]].pack({position:'absolute', top:0, right:rapad[i-1]}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); - } - // this.axes.y2axis.pack({position:'absolute', top:0, right:0}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top}); - - this.target.append(this.grid.createElement(this._gridPadding)); - this.grid.draw(); - - // put the shadow canvases behind the series canvases so shadows don't overlap on stacked bars. - for (i=0; i<this.series.length; i++) { - this.target.append(this.series[i].shadowCanvas.createElement(this._gridPadding, 'jqplot-series-canvas jqplot-shadow')); - this.series[i].shadowCanvas.setContext(); - } - - for (i=0; i<this.series.length; i++) { - this.target.append(this.series[i].canvas.createElement(this._gridPadding, 'jqplot-series-canvas')); - this.series[i].canvas.setContext(); - } - - // var sctx = this.seriesCanvas.setContext(); - this.target.append(this.eventCanvas.createElement(this._gridPadding, 'jqplot-event-canvas')); - var ectx = this.eventCanvas.setContext(); - ectx.fillStyle = 'rgba(0,0,0,0)'; - ectx.fillRect(0,0,ectx.canvas.width, ectx.canvas.height); - - // bind custom event handlers to regular events. - this.bindCustomEvents(); - - // draw legend before series if the series needs to know the legend dimensions. - if (this.legend.preDraw) { - this.target.append(this.legend.draw()); - this.legend.pack(this._gridPadding); - if (this.legend._elem) { - this.drawSeries({legendInfo:{location:this.legend.location, width:this.legend.getWidth(), height:this.legend.getHeight(), xoffset:this.legend.xoffset, yoffset:this.legend.yoffset}}); - } - else { - this.drawSeries(); - } - } - else { // draw series before legend - this.drawSeries(); - $(this.series[this.series.length-1].canvas._elem).after(this.legend.draw()); - // this.target.append(this.legend.draw()); - this.legend.pack(this._gridPadding); - } - - // register event listeners on the overlay canvas - for (var i=0; i<$.jqplot.eventListenerHooks.length; i++) { - var h = $.jqplot.eventListenerHooks[i]; - // in the handler, this will refer to the eventCanvas dom element. - // make sure there are references back into plot objects. - this.eventCanvas._elem.bind(h[0], {plot:this}, h[1]); - } - - for (var i=0; i<$.jqplot.postDrawHooks.length; i++) { - $.jqplot.postDrawHooks[i].call(this); - } - - if (this.target.is(':visible')) { - this._drawCount += 1; - } - - this.target.trigger('jqplotPostDraw', [this]); - } - }; - - this.bindCustomEvents = function() { - this.eventCanvas._elem.bind('click', {plot:this}, this.onClick); - this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick); - this.eventCanvas._elem.bind('mousedown', {plot:this}, this.onMouseDown); - this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onMouseUp); - this.eventCanvas._elem.bind('mousemove', {plot:this}, this.onMouseMove); - this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter); - this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave); - }; - - function getEventPosition(ev) { - var plot = ev.data.plot; - // var xaxis = plot.axes.xaxis; - // var x2axis = plot.axes.x2axis; - // var yaxis = plot.axes.yaxis; - // var y2axis = plot.axes.y2axis; - var offsets = plot.eventCanvas._elem.offset(); - var gridPos = {x:ev.pageX - offsets.left, y:ev.pageY - offsets.top}; - // var dataPos = {x1y1:{x:null, y:null}, x1y2:{x:null, y:null}, x2y1:{x:null, y:null}, x2y2:{x:null, y:null}}; - var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null}; - - var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; - var ax = plot.axes; - for (var n=11; n>0; n--) { - var axis = an[n-1]; - if (ax[axis].show) { - dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); - } - } - - return ({offsets:offsets, gridPos:gridPos, dataPos:dataPos}); - } - - function getNeighborPoint(plot, x, y) { - var ret = null; - var s, i, d0, d, j, r; - var threshold; - for (var i=0; i<plot.series.length; i++) { - s = plot.series[i]; - r = s.renderer; - if (s.show) { - threshold = Math.abs(s.markerRenderer.size/2+s.neighborThreshold); - for (var j=0; j<s.gridData.length; j++) { - p = s.gridData[j]; - // neighbor looks different to OHLC chart. - if (r.constructor == $.jqplot.OHLCRenderer) { - if (r.candleStick) { - var yp = s._yaxis.series_u2p; - if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { - ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; - } - } - // if an open hi low close chart - else if (!r.hlc){ - var yp = s._yaxis.series_u2p; - if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) { - ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; - } - } - // a hi low close chart - else { - var yp = s._yaxis.series_u2p; - if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) { - ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; - } - } - - } - else { - d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) ); - if (d <= threshold && (d <= d0 || d0 == null)) { - d0 = d; - ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}; - } - } - } - } - } - return ret; - } - - this.onClick = function(ev) { - // Event passed in is unnormalized and will have data attribute. - // Event passed out in normalized and won't have data attribute. - var positions = getEventPosition(ev); - var p = ev.data.plot; - var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y); - ev.data.plot.eventCanvas._elem.trigger('jqplotClick', [positions.gridPos, positions.dataPos, neighbor, p]); - }; - - this.onDblClick = function(ev) { - // Event passed in is unnormalized and will have data attribute. - // Event passed out in normalized and won't have data attribute. - var positions = getEventPosition(ev); - var p = ev.data.plot; - var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y); - ev.data.plot.eventCanvas._elem.trigger('jqplotDblClick', [positions.gridPos, positions.dataPos, neighbor, p]); - }; - - this.onMouseDown = function(ev) { - var positions = getEventPosition(ev); - var p = ev.data.plot; - var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y); - ev.data.plot.eventCanvas._elem.trigger('jqplotMouseDown', [positions.gridPos, positions.dataPos, neighbor, p]); - }; - - this.onMouseUp = function(ev) { - var positions = getEventPosition(ev); - ev.data.plot.eventCanvas._elem.trigger('jqplotMouseUp', [positions.gridPos, positions.dataPos, null, ev.data.plot]); - }; - - this.onMouseMove = function(ev) { - var positions = getEventPosition(ev); - var p = ev.data.plot; - var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y); - ev.data.plot.eventCanvas._elem.trigger('jqplotMouseMove', [positions.gridPos, positions.dataPos, neighbor, p]); - }; - - this.onMouseEnter = function(ev) { - var positions = getEventPosition(ev); - var p = ev.data.plot; - ev.data.plot.eventCanvas._elem.trigger('jqplotMouseEnter', [positions.gridPos, positions.dataPos, null, p]); - }; - - this.onMouseLeave = function(ev) { - var positions = getEventPosition(ev); - var p = ev.data.plot; - ev.data.plot.eventCanvas._elem.trigger('jqplotMouseLeave', [positions.gridPos, positions.dataPos, null, p]); - }; - - // convienece function to draw series shadows and series. - this.drawSeries = function(options, idx){ - var i, series, ctx; - // draw specified series - if (idx != undefined) { - series = this.series[idx]; - ctx = series.shadowCanvas._ctx; - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); - series.drawShadow(ctx, options, this); - ctx = series.canvas._ctx; - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); - series.draw(ctx, options, this); - } - - else { - // if call series drawShadow method first, in case all series shadows - // should be drawn before any series. This will ensure, like for - // stacked bar plots, that shadows don't overlap series. - for (i=0; i<this.series.length; i++) { - // first clear the canvas - series = this.series[i]; - ctx = series.shadowCanvas._ctx; - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); - series.drawShadow(ctx, options, this); - ctx = series.canvas._ctx; - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); - series.draw(ctx, options, this); - } - } - }; - } - - - $.jqplot.ColorGenerator = function(colors) { - var idx = 0; - - this.next = function () { - if (idx < colors.length) { - return colors[idx++]; - } - else { - idx = 0; - return colors[idx++]; - } - }; - - this.previous = function () { - if (idx > 0) { - return colors[idx--]; - } - else { - idx = colors.length-1; - return colors[idx]; - } - }; - - // get a color by index without advancing pointer. - this.get = function(i) { - return colors[i]; - }; - - this.setColors = function(c) { - colors = c; - }; - - this.reset = function() { - idx = 0; - }; - }; - - // convert a hex color string to rgb string. - // h - 3 or 6 character hex string, with or without leading # - // a - optional alpha - $.jqplot.hex2rgb = function(h, a) { - h = h.replace('#', ''); - if (h.length == 3) { - h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2]; - } - var rgb; - rgb = 'rgba('+parseInt(h.slice(0,2), 16)+', '+parseInt(h.slice(2,4), 16)+', '+parseInt(h.slice(4,6), 16); - if (a) { - rgb += ', '+a; - } - rgb += ')'; - return rgb; - }; - - // convert an rgb color spec to a hex spec. ignore any alpha specification. - $.jqplot.rgb2hex = function(s) { - var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/; - var m = s.match(pat); - var h = '#'; - for (i=1; i<4; i++) { - var temp; - if (m[i].search(/%/) != -1) { - temp = parseInt(255*m[i]/100, 10).toString(16); - if (temp.length == 1) { - temp = '0'+temp; - } - } - else { - temp = parseInt(m[i], 10).toString(16); - if (temp.length == 1) { - temp = '0'+temp; - } - } - h += temp; - } - return h; - }; - - // given a css color spec, return an rgb css color spec - $.jqplot.normalize2rgb = function(s, a) { - if (s.search(/^ *rgba?\(/) != -1) { - return s; - } - else if (s.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) { - return $.jqplot.hex2rgb(s, a); - } - else { - throw 'invalid color spec'; - } - }; - - // extract the r, g, b, a color components out of a css color spec. - $.jqplot.getColorComponents = function(s) { - var rgb = $.jqplot.normalize2rgb(s); - var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/; - var m = rgb.match(pat); - var ret = []; - for (i=1; i<4; i++) { - if (m[i].search(/%/) != -1) { - ret[i-1] = parseInt(255*m[i]/100, 10); - } - else { - ret[i-1] = parseInt(m[i], 10); - } - } - ret[3] = parseFloat(m[4]) ? parseFloat(m[4]) : 1.0; - return ret; - }; - - // Convienence function that won't hang IE. - $.jqplot.log = function() { - if (window.console && $.jqplot.debug) { - if (arguments.length == 1) { - console.log (arguments[0]); - } - else { - console.log(arguments); - } - } - }; - var log = $.jqplot.log; - - - // class: $.jqplot.AxisLabelRenderer - // Renderer to place labels on the axes. - $.jqplot.AxisLabelRenderer = function(options) { - // Group: Properties - $.jqplot.ElemContainer.call(this); - // name of the axis associated with this tick - this.axis; - // prop: show - // wether or not to show the tick (mark and label). - this.show = true; - // prop: label - // The text or html for the label. - this.label = ''; - this._elem; - // prop: escapeHTML - // true to escape HTML entities in the label. - this.escapeHTML = false; - - $.extend(true, this, options); - }; - - $.jqplot.AxisLabelRenderer.prototype = new $.jqplot.ElemContainer(); - $.jqplot.AxisLabelRenderer.prototype.constructor = $.jqplot.AxisLabelRenderer; - - $.jqplot.AxisLabelRenderer.prototype.init = function(options) { - $.extend(true, this, options); - }; - - $.jqplot.AxisLabelRenderer.prototype.draw = function() { - this._elem = $('<div style="position:absolute;" class="jqplot-'+this.axis+'-label"></div>'); - - if (Number(this.label)) { - this._elem.css('white-space', 'nowrap'); - } - - if (!this.escapeHTML) { - this._elem.html(this.label); - } - else { - this._elem.text(this.label); - } - - return this._elem; - }; - - $.jqplot.AxisLabelRenderer.prototype.pack = function() { - }; - - // class: $.jqplot.AxisTickRenderer - // A "tick" object showing the value of a tick/gridline on the plot. - $.jqplot.AxisTickRenderer = function(options) { - // Group: Properties - $.jqplot.ElemContainer.call(this); - // prop: mark - // tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null. - this.mark = 'outside'; - // name of the axis associated with this tick - this.axis; - // prop: showMark - // wether or not to show the mark on the axis. - this.showMark = true; - // prop: showGridline - // wether or not to draw the gridline on the grid at this tick. - this.showGridline = true; - // prop: isMinorTick - // if this is a minor tick. - this.isMinorTick = false; - // prop: size - // Length of the tick beyond the grid in pixels. - // DEPRECATED: This has been superceeded by markSize - this.size = 4; - // prop: markSize - // Length of the tick marks in pixels. For 'cross' style, length - // will be stoked above and below axis, so total length will be twice this. - this.markSize = 6; - // prop: show - // wether or not to show the tick (mark and label). - // Setting this to false requires more testing. It is recommended - // to set showLabel and showMark to false instead. - this.show = true; - // prop: showLabel - // wether or not to show the label. - this.showLabel = true; - this.label = ''; - this.value = null; - this._styles = {}; - // prop: formatter - // A class of a formatter for the tick text. sprintf by default. - this.formatter = $.jqplot.DefaultTickFormatter; - // prop: formatString - // string passed to the formatter. - this.formatString = ''; - // prop: fontFamily - // css spec for the font-family css attribute. - this.fontFamily; - // prop: fontSize - // css spec for the font-size css attribute. - this.fontSize; - // prop: textColor - // css spec for the color attribute. - this.textColor; - this._elem; - - $.extend(true, this, options); - }; - - $.jqplot.AxisTickRenderer.prototype.init = function(options) { - $.extend(true, this, options); - }; - - $.jqplot.AxisTickRenderer.prototype = new $.jqplot.ElemContainer(); - $.jqplot.AxisTickRenderer.prototype.constructor = $.jqplot.AxisTickRenderer; - - $.jqplot.AxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) { - this.value = value; - this.axis = axisName; - if (isMinor) { - this.isMinorTick = true; - } - return this; - }; - - $.jqplot.AxisTickRenderer.prototype.draw = function() { - if (!this.label) { - this.label = this.formatter(this.formatString, this.value); - } - style ='style="position:absolute;'; - if (Number(this.label)) { - style +='white-space:nowrap;'; - } - style += '"'; - this._elem = $('<div '+style+' class="jqplot-'+this.axis+'-tick">'+this.label+'</div>'); - for (var s in this._styles) { - this._elem.css(s, this._styles[s]); - } - if (this.fontFamily) { - this._elem.css('font-family', this.fontFamily); - } - if (this.fontSize) { - this._elem.css('font-size', this.fontSize); - } - if (this.textColor) { - this._elem.css('color', this.textColor); - } - return this._elem; - }; - - $.jqplot.DefaultTickFormatter = function (format, val) { - if (typeof val == 'number') { - if (!format) { - format = '%.1f'; - } - return $.jqplot.sprintf(format, val); - } - else { - return String(val); - } - }; - - $.jqplot.AxisTickRenderer.prototype.pack = function() { - }; - - // Class: $.jqplot.CanvasGridRenderer - // The default jqPlot grid renderer, creating a grid on a canvas element. - // The renderer has no additional options beyond the <Grid> class. - $.jqplot.CanvasGridRenderer = function(){ - this.shadowRenderer = new $.jqplot.ShadowRenderer(); - }; - - // called with context of Grid object - $.jqplot.CanvasGridRenderer.prototype.init = function(options) { - this._ctx; - $.extend(true, this, options); - // set the shadow renderer options - var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false}; - this.renderer.shadowRenderer.init(sopts); - }; - - // called with context of Grid. - $.jqplot.CanvasGridRenderer.prototype.createElement = function() { - var elem = document.createElement('canvas'); - var w = this._plotDimensions.width; - var h = this._plotDimensions.height; - elem.width = w; - elem.height = h; - this._elem = $(elem); - this._elem.addClass('jqplot-grid-canvas'); - this._elem.css({ position: 'absolute', left: 0, top: 0 }); - if ($.browser.msie) { - window.G_vmlCanvasManager.init_(document); - } - if ($.browser.msie) { - elem = window.G_vmlCanvasManager.initElement(elem); - } - this._top = this._offsets.top; - this._bottom = h - this._offsets.bottom; - this._left = this._offsets.left; - this._right = w - this._offsets.right; - this._width = this._right - this._left; - this._height = this._bottom - this._top; - return this._elem; - }; - - $.jqplot.CanvasGridRenderer.prototype.draw = function() { - this._ctx = this._elem.get(0).getContext("2d"); - var ctx = this._ctx; - var axes = this._axes; - // Add the grid onto the grid canvas. This is the bottom most layer. - ctx.save(); - ctx.fillStyle = this.background; - ctx.fillRect(this._left, this._top, this._width, this._height); - - if (this.drawGridlines) { - ctx.save(); - ctx.lineJoin = 'miter'; - ctx.lineCap = 'butt'; - ctx.lineWidth = this.gridLineWidth; - ctx.strokeStyle = this.gridLineColor; - var b, e; - var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis']; - for (var i=4; i>0; i--) { - var name = ax[i-1]; - var axis = axes[name]; - var ticks = axis._ticks; - if (axis.show) { - for (var j=ticks.length; j>0; j--) { - var t = ticks[j-1]; - if (t.show) { - var pos = Math.round(axis.u2p(t.value)) + 0.5; - switch (name) { - case 'xaxis': - // draw the grid line - if (t.showGridline) { - drawLine(pos, this._top, pos, this._bottom); - } - - // draw the mark - if (t.showMark && t.mark) { - s = t.markSize; - m = t.mark; - var pos = Math.round(axis.u2p(t.value)) + 0.5; - switch (m) { - case 'outside': - b = this._bottom; - e = this._bottom+s; - break; - case 'inside': - b = this._bottom-s; - e = this._bottom; - break; - case 'cross': - b = this._bottom-s; - e = this._bottom+s; - break; - default: - b = this._bottom; - e = this._bottom+s; - break; - } - // draw the shadow - if (this.shadow) { - this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false}); - } - // draw the line - drawLine(pos, b, pos, e); - } - break; - case 'yaxis': - // draw the grid line - if (t.showGridline) { - drawLine(this._right, pos, this._left, pos); - } - // draw the mark - if (t.showMark && t.mark) { - s = t.markSize; - m = t.mark; - var pos = Math.round(axis.u2p(t.value)) + 0.5; - switch (m) { - case 'outside': - b = this._left-s; - e = this._left; - break; - case 'inside': - b = this._left; - e = this._left+s; - break; - case 'cross': - b = this._left-s; - e = this._left+s; - break; - default: - b = this._left-s; - e = this._left; - break; - } - // draw the shadow - if (this.shadow) { - this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); - } - drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); - } - break; - case 'x2axis': - // draw the grid line - if (t.showGridline) { - drawLine(pos, this._bottom, pos, this._top); - } - // draw the mark - if (t.showMark && t.mark) { - s = t.markSize; - m = t.mark; - var pos = Math.round(axis.u2p(t.value)) + 0.5; - switch (m) { - case 'outside': - b = this._top-s; - e = this._top; - break; - case 'inside': - b = this._top; - e = this._top+s; - break; - case 'cross': - b = this._top-s; - e = this._top+s; - break; - default: - b = this._top-s; - e = this._top; - break; - } - // draw the shadow - if (this.shadow) { - this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false}); - } - drawLine(pos, b, pos, e); - } - break; - case 'y2axis': - // draw the grid line - if (t.showGridline) { - drawLine(this._left, pos, this._right, pos); - } - // draw the mark - if (t.showMark && t.mark) { - s = t.markSize; - m = t.mark; - var pos = Math.round(axis.u2p(t.value)) + 0.5; - switch (m) { - case 'outside': - b = this._right; - e = this._right+s; - break; - case 'inside': - b = this._right-s; - e = this._right; - break; - case 'cross': - b = this._right-s; - e = this._right+s; - break; - default: - b = this._right; - e = this._right+s; - break; - } - // draw the shadow - if (this.shadow) { - this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); - } - drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); - } - break; - default: - break; - } - } - } - } - } - // Now draw grid lines for additional y axes - ax = ['y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; - for (var i=7; i>0; i--) { - var axis = axes[ax[i-1]]; - var ticks = axis._ticks; - if (axis.show) { - var tn = ticks[axis.numberTicks-1]; - var t0 = ticks[0]; - var left = axis.getLeft(); - var points = [[left, tn.getTop() + tn.getHeight()/2], [left, t0.getTop() + t0.getHeight()/2 + 1.0]]; - // draw the shadow - if (this.shadow) { - this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', fill:false, closePath:false}); - } - // draw the line - drawLine(points[0][0], points[0][1], points[1][0], points[1][1], {lineCap:'butt', strokeStyle:axis.borderColor, lineWidth:axis.borderWidth}); - // draw the tick marks - for (var j=ticks.length; j>0; j--) { - var t = ticks[j-1]; - s = t.markSize; - m = t.mark; - var pos = Math.round(axis.u2p(t.value)) + 0.5; - if (t.showMark && t.mark) { - switch (m) { - case 'outside': - b = left; - e = left+s; - break; - case 'inside': - b = left-s; - e = left; - break; - case 'cross': - b = left-s; - e = left+s; - break; - default: - b = left; - e = left+s; - break; - } - points = [[b,pos], [e,pos]]; - // draw the shadow - if (this.shadow) { - this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false}); - } - // draw the line - drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor}); - } - } - } - } - - ctx.restore(); - } - - function drawLine(bx, by, ex, ey, opts) { - ctx.save(); - opts = opts || {}; - $.extend(true, ctx, opts); - ctx.beginPath(); - ctx.moveTo(bx, by); - ctx.lineTo(ex, ey); - ctx.stroke(); - ctx.restore(); - } - - if (this.shadow) { - var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]]; - this.renderer.shadowRenderer.draw(ctx, points); - } - // Now draw border around grid. Use axis border definitions. start at - // upper left and go clockwise. - drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth}); - drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth}); - drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth}); - drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth}); - // ctx.lineWidth = this.borderWidth; - // ctx.strokeStyle = this.borderColor; - // ctx.strokeRect(this._left, this._top, this._width, this._height); - - - ctx.restore(); - }; - - /** - * Date instance methods - * - * @author Ken Snyder (ken d snyder at gmail dot com) - * @date 2008-09-10 - * @version 2.0.2 (http://kendsnyder.com/sandbox/date/) - * @license Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/) - * - * @contributions Chris Leonello - * @comment Bug fix to 12 hour time and additions to handle milliseconds and - * @comment 24 hour time without am/pm suffix - * - */ - - // begin by creating a scope for utility variables - - // - // pre-calculate the number of milliseconds in a day - // - - var day = 24 * 60 * 60 * 1000; - // - // function to add leading zeros - // - var zeroPad = function(number, digits) { - number = String(number); - while (number.length < digits) { - number = '0' + number; - } - return number; - }; - // - // set up integers and functions for adding to a date or subtracting two dates - // - var multipliers = { - millisecond: 1, - second: 1000, - minute: 60 * 1000, - hour: 60 * 60 * 1000, - day: day, - week: 7 * day, - month: { - // add a number of months - add: function(d, number) { - // add any years needed (increments of 12) - multipliers.year.add(d, Math[number > 0 ? 'floor' : 'ceil'](number / 12)); - // ensure that we properly wrap betwen December and January - var prevMonth = d.getMonth() + (number % 12); - if (prevMonth == 12) { - prevMonth = 0; - d.setYear(d.getFullYear() + 1); - } else if (prevMonth == -1) { - prevMonth = 11; - d.setYear(d.getFullYear() - 1); - } - d.setMonth(prevMonth); - }, - // get the number of months between two Date objects (decimal to the nearest day) - diff: function(d1, d2) { - // get the number of years - var diffYears = d1.getFullYear() - d2.getFullYear(); - // get the number of remaining months - var diffMonths = d1.getMonth() - d2.getMonth() + (diffYears * 12); - // get the number of remaining days - var diffDays = d1.getDate() - d2.getDate(); - // return the month difference with the days difference as a decimal - return diffMonths + (diffDays / 30); - } - }, - year: { - // add a number of years - add: function(d, number) { - d.setYear(d.getFullYear() + Math[number > 0 ? 'floor' : 'ceil'](number)); - }, - // get the number of years between two Date objects (decimal to the nearest day) - diff: function(d1, d2) { - return multipliers.month.diff(d1, d2) / 12; - } - } - }; - // - // alias each multiplier with an 's' to allow 'year' and 'years' for example - // - for (var unit in multipliers) { - if (unit.substring(unit.length - 1) != 's') { // IE will iterate newly added properties :| - multipliers[unit + 's'] = multipliers[unit]; - } - } - // - // take a date instance and a format code and return the formatted value - // - var format = function(d, code) { - if (Date.prototype.strftime.formatShortcuts[code]) { - // process any shortcuts recursively - return d.strftime(Date.prototype.strftime.formatShortcuts[code]); - } else { - // get the format code function and toPaddedString() argument - var getter = (Date.prototype.strftime.formatCodes[code] || '').split('.'); - var nbr = d['get' + getter[0]] ? d['get' + getter[0]]() : ''; - // run toPaddedString() if specified - if (getter[1]) { - nbr = zeroPad(nbr, getter[1]); - } - // prepend the leading character - return nbr; - } - }; - // - // Add methods to Date instances - // - var instanceMethods = { - // - // Return a date one day ahead (or any other unit) - // - // @param string unit - // units: year | month | day | week | hour | minute | second | millisecond - // @return object Date - // - succ: function(unit) { - return this.clone().add(1, unit); - }, - // - // Add an arbitrary amount to the currently stored date - // - // @param integer/float number - // @param string unit - // @return object Date (chainable) - // - add: function(number, unit) { - var factor = multipliers[unit] || multipliers.day; - if (typeof factor == 'number') { - this.setTime(this.getTime() + (factor * number)); - } else { - factor.add(this, number); - } - return this; - }, - // - // Find the difference between the current and another date - // - // @param string/object dateObj - // @param string unit - // @param boolean allowDecimal - // @return integer/float - // - diff: function(dateObj, unit, allowDecimal) { - // ensure we have a Date object - dateObj = Date.create(dateObj); - if (dateObj === null) { - return null; - } - // get the multiplying factor integer or factor function - var factor = multipliers[unit] || multipliers.day; - if (typeof factor == 'number') { - // multiply - var unitDiff = (this.getTime() - dateObj.getTime()) / factor; - } else { - // run function - var unitDiff = factor.diff(this, dateObj); - } - // if decimals are not allowed, round toward zero - return (allowDecimal ? unitDiff : Math[unitDiff > 0 ? 'floor' : 'ceil'](unitDiff)); - }, - // - // Convert a date to a string using traditional strftime format codes - // - // @param string formatStr - // @return string - // - strftime: function(formatStr) { - // default the format string to year-month-day - var source = formatStr || '%Y-%m-%d', result = '', match; - // replace each format code - while (source.length > 0) { - if (match = source.match(Date.prototype.strftime.formatCodes.matcher)) { - result += source.slice(0, match.index); - result += (match[1] || '') + format(this, match[2]); - source = source.slice(match.index + match[0].length); - } else { - result += source; - source = ''; - } - } - return result; - }, - // - // Return a proper two-digit year integer - // - // @return integer - // - getShortYear: function() { - return this.getYear() % 100; - }, - // - // Get the number of the current month, 1-12 - // - // @return integer - // - getMonthNumber: function() { - return this.getMonth() + 1; - }, - // - // Get the name of the current month - // - // @return string - // - getMonthName: function() { - return Date.MONTHNAMES[this.getMonth()]; - }, - // - // Get the abbreviated name of the current month - // - // @return string - // - getAbbrMonthName: function() { - return Date.ABBR_MONTHNAMES[this.getMonth()]; - }, - // - // Get the name of the current week day - // - // @return string - // - getDayName: function() { - return Date.DAYNAMES[this.getDay()]; - }, - // - // Get the abbreviated name of the current week day - // - // @return string - // - getAbbrDayName: function() { - return Date.ABBR_DAYNAMES[this.getDay()]; - }, - // - // Get the ordinal string associated with the day of the month (i.e. st, nd, rd, th) - // - // @return string - // - getDayOrdinal: function() { - return Date.ORDINALNAMES[this.getDate() % 10]; - }, - // - // Get the current hour on a 12-hour scheme - // - // @return integer - // - getHours12: function() { - var hours = this.getHours(); - return hours > 12 ? hours - 12 : (hours == 0 ? 12 : hours); - }, - // - // Get the AM or PM for the current time - // - // @return string - // - getAmPm: function() { - return this.getHours() >= 12 ? 'PM' : 'AM'; - }, - // - // Get the current date as a Unix timestamp - // - // @return integer - // - getUnix: function() { - return Math.round(this.getTime() / 1000, 0); - }, - // - // Get the GMT offset in hours and minutes (e.g. +06:30) - // - // @return string - // - getGmtOffset: function() { - // divide the minutes offset by 60 - var hours = this.getTimezoneOffset() / 60; - // decide if we are ahead of or behind GMT - var prefix = hours < 0 ? '+' : '-'; - // remove the negative sign if any - hours = Math.abs(hours); - // add the +/- to the padded number of hours to : to the padded minutes - return prefix + zeroPad(Math.floor(hours), 2) + ':' + zeroPad((hours % 1) * 60, 2); - }, - // - // Get the browser-reported name for the current timezone (e.g. MDT, Mountain Daylight Time) - // - // @return string - // - getTimezoneName: function() { - var match = /(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString()); - return match[1] || match[2] || 'GMT' + this.getGmtOffset(); - }, - // - // Convert the current date to an 8-digit integer (%Y%m%d) - // - // @return int - // - toYmdInt: function() { - return (this.getFullYear() * 10000) + (this.getMonthNumber() * 100) + this.getDate(); - }, - // - // Create a copy of a date object - // - // @return object - // - clone: function() { - return new Date(this.getTime()); - } - }; - for (var name in instanceMethods) { - Date.prototype[name] = instanceMethods[name]; - } - // - // Add static methods to the date object - // - var staticMethods = { - // - // The heart of the date functionality: returns a date object if given a convertable value - // - // @param string/object/integer date - // @return object Date - // - create: function(date) { - // If the passed value is already a date object, return it - if (date instanceof Date) { - return date; - } - // if (typeof date == 'number') return new Date(date * 1000); - // If the passed value is an integer, interpret it as a javascript timestamp - if (typeof date == 'number') { - return new Date(date); - } - // If the passed value is a string, attempt to parse it using Date.parse() - var parsable = String(date).replace(/^\s*(.+)\s*$/, '$1'), i = 0, length = Date.create.patterns.length, pattern; - var current = parsable; - while (i < length) { - ms = Date.parse(current); - if (!isNaN(ms)) { - return new Date(ms); - } - pattern = Date.create.patterns[i]; - if (typeof pattern == 'function') { - obj = pattern(current); - if (obj instanceof Date) { - return obj; - } - } else { - current = parsable.replace(pattern[0], pattern[1]); - } - i++; - } - return NaN; - }, - // - // constants representing month names, day names, and ordinal names - // (same names as Ruby Date constants) - // - MONTHNAMES : 'January February March April May June July August September October November December'.split(' '), - ABBR_MONTHNAMES : 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' '), - DAYNAMES : 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' '), - ABBR_DAYNAMES : 'Sun Mon Tue Wed Thu Fri Sat'.split(' '), - ORDINALNAMES : 'th st nd rd th th th th th th'.split(' '), - // - // Shortcut for full ISO-8601 date conversion - // - ISO: '%Y-%m-%dT%H:%M:%S.%N%G', - // - // Shortcut for SQL-type formatting - // - SQL: '%Y-%m-%d %H:%M:%S', - // - // Setter method for month, day, and ordinal names for i18n - // - // @param object newNames - // - daysInMonth: function(year, month) { - if (month == 2) { - return new Date(year, 1, 29).getDate() == 29 ? 29 : 28; - } - return [undefined,31,undefined,31,30,31,30,31,31,30,31,30,31][month]; - } - }; - for (var name in staticMethods) { - Date[name] = staticMethods[name]; - } - // - // format codes for strftime - // - // each code must be an array where the first member is the name of a Date.prototype function - // and optionally a second member indicating the number to pass to Number#toPaddedString() - // - Date.prototype.strftime.formatCodes = { - // - // 2-part regex matcher for format codes - // - // first match must be the character before the code (to account for escaping) - // second match must be the format code character(s) - // - matcher: /()%(#?(%|[a-z]))/i, - // year - Y: 'FullYear', - y: 'ShortYear.2', - // month - m: 'MonthNumber.2', - '#m': 'MonthNumber', - B: 'MonthName', - b: 'AbbrMonthName', - // day - d: 'Date.2', - '#d': 'Date', - e: 'Date', - A: 'DayName', - a: 'AbbrDayName', - w: 'Day', - o: 'DayOrdinal', - // hours - H: 'Hours.2', - '#H': 'Hours', - I: 'Hours12.2', - '#I': 'Hours12', - p: 'AmPm', - // minutes - M: 'Minutes.2', - '#M': 'Minutes', - // seconds - S: 'Seconds.2', - '#S': 'Seconds', - s: 'Unix', - // milliseconds - N: 'Milliseconds.3', - '#N': 'Milliseconds', - // timezone - O: 'TimezoneOffset', - Z: 'TimezoneName', - G: 'GmtOffset' - }; - // - // shortcuts that will be translated into their longer version - // - // be sure that format shortcuts do not refer to themselves: this will cause an infinite loop - // - Date.prototype.strftime.formatShortcuts = { - // date - F: '%Y-%m-%d', - // time - T: '%H:%M:%S', - X: '%H:%M:%S', - // local format date - x: '%m/%d/%y', - D: '%m/%d/%y', - // local format extended - '#c': '%a %b %e %H:%M:%S %Y', - // local format short - v: '%e-%b-%Y', - R: '%H:%M', - r: '%I:%M:%S %p', - // tab and newline - t: '\t', - n: '\n', - '%': '%' - }; - // - // A list of conversion patterns (array arguments sent directly to gsub) - // Add, remove or splice a patterns to customize date parsing ability - // - Date.create.patterns = [ - [/-/g, '/'], // US-style time with dashes => Parsable US-style time - [/st|nd|rd|th/g, ''], // remove st, nd, rd and th - [/(3[01]|[0-2]\d)\s*\.\s*(1[0-2]|0\d)\s*\.\s*([1-9]\d{3})/, '$2/$1/$3'], // World time => Parsable US-style time - [/([1-9]\d{3})\s*-\s*(1[0-2]|0\d)\s*-\s*(3[01]|[0-2]\d)/, '$2/$3/$1'], // ISO-style time => Parsable US-style time - function(str) { // 12-hour or 24 hour time with milliseconds - // var match = str.match(/^(?:(.+)\s+)?([1-9]|1[012])(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d))?\s*(am|pm)\s*$/i); - var match = str.match(/^(?:(.+)\s+)?([012]?\d)(?:\s*\:\s*(\d\d))?(?:\s*\:\s*(\d\d(\.\d*)?))?\s*(am|pm)?\s*$/i); - // opt. date hour opt. minute opt. second opt. msec opt. am or pm - if (match) { - if (match[1]) { - var d = Date.create(match[1]); - if (isNaN(d)) { - return; - } - } else { - var d = new Date(); - d.setMilliseconds(0); - } - var hour = parseFloat(match[2]); - if (match[6]) { - hour = match[6].toLowerCase() == 'am' ? (hour == 12 ? 0 : hour) : (hour == 12 ? 12 : hour + 12); - } - d.setHours(hour, parseInt(match[3] || 0, 10), parseInt(match[4] || 0, 10), ((parseFloat(match[5] || 0)) || 0)*1000); - return d; - } - else { - return str; - } - }, - function(str) { // ISO timestamp with time zone. - var match = str.match(/^(?:(.+))[T|\s+]([012]\d)(?:\:(\d\d))(?:\:(\d\d))(?:\.\d+)([\+\-]\d\d\:\d\d)$/i); - if (match) { - if (match[1]) { - var d = Date.create(match[1]); - if (isNaN(d)) { - return; - } - } else { - var d = new Date(); - d.setMilliseconds(0); - } - var hour = parseFloat(match[2]); - d.setHours(hour, parseInt(match[3], 10), parseInt(match[4], 10), parseFloat(match[5])*1000); - return d; - } - else { - return str; - } - }, - function(str) { - var match = str.match(/^([0-3]?\d)\s*[-\/.\s]{1}\s*([a-zA-Z]{3,9})\s*[-\/.\s]{1}\s*([0-3]?\d)$/); - if (match) { - var d = new Date(); - var y = parseFloat(String(d.getFullYear()).slice(2,4)); - var cent = parseInt(String(d.getFullYear())/100, 10)*100; - var centoffset = 1; - var m1 = parseFloat(match[1]); - var m3 = parseFloat(match[3]); - var ny, nd, nm; - if (m1 > 31) { // first number is a year - nd = match[3]; - if (m1 < y+centoffset) { // if less than 1 year out, assume it is this century. - ny = cent + m1; - } - else { - ny = cent - 100 + m1; - } - } - - else { // last number is the year - nd = match[1]; - if (m3 < y+centoffset) { // if less than 1 year out, assume it is this century. - ny = cent + m3; - } - else { - ny = cent - 100 + m3; - } - } - - var nm = $.inArray(match[2], Date.ABBR_MONTHNAMES); - - if (nm == -1) { - nm = $.inArray(match[2], Date.MONTHNAMES); - } - - d.setFullYear(ny, nm, nd); - d.setHours(0,0,0,0); - return d; - } - - else { - return str; - } - } - ]; - - if ($.jqplot.config.debug) { - $.date = Date.create; - } - - // Class: $.jqplot.DivTitleRenderer - // The default title renderer for jqPlot. This class has no options beyond the <Title> class. - $.jqplot.DivTitleRenderer = function() { - }; - - $.jqplot.DivTitleRenderer.prototype.init = function(options) { - $.extend(true, this, options); - }; - - $.jqplot.DivTitleRenderer.prototype.draw = function() { - var r = this.renderer; - if (!this.text) { - this.show = false; - this._elem = $('<div style="height:0px;width:0px;"></div>'); - } - else if (this.text) { - // don't trust that a stylesheet is present, set the position. - var styletext = 'position:absolute;top:0px;left:0px;'; - styletext += (this._plotWidth) ? 'width:'+this._plotWidth+'px;' : ''; - styletext += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; - styletext += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; - styletext += (this.textAlign) ? 'text-align:'+this.textAlign+';' : 'text-align:center;'; - styletext += (this.textColor) ? 'color:'+this.textColor+';' : ''; - this._elem = $('<div class="jqplot-title" style="'+styletext+'">'+this.text+'</div>'); - } - - return this._elem; - }; - - $.jqplot.DivTitleRenderer.prototype.pack = function() { - // nothing to do here - }; - - // Class: $.jqplot.LineRenderer - // The default line renderer for jqPlot, this class has no options beyond the <Series> class. - // Draws series as a line. - $.jqplot.LineRenderer = function(){ - this.shapeRenderer = new $.jqplot.ShapeRenderer(); - this.shadowRenderer = new $.jqplot.ShadowRenderer(); - }; - - // called with scope of series. - $.jqplot.LineRenderer.prototype.init = function(options) { - $.extend(true, this.renderer, options); - // set the shape renderer options - var opts = {lineJoin:'round', lineCap:'round', fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, closePath:this.fill}; - this.renderer.shapeRenderer.init(opts); - // set the shadow renderer options - // scale the shadowOffset to the width of the line. - if (this.lineWidth > 2.5) { - var shadow_offset = this.shadowOffset* (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6); - // var shadow_offset = this.shadowOffset; - } - // for skinny lines, don't make such a big shadow. - else { - var shadow_offset = this.shadowOffset*Math.atan((this.lineWidth/2.5))/0.785398163; - } - var sopts = {lineJoin:'round', lineCap:'round', fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, closePath:this.fill}; - this.renderer.shadowRenderer.init(sopts); - }; - - // Method: setGridData - // converts the user data values to grid coordinates and stores them - // in the gridData array. - // Called with scope of a series. - $.jqplot.LineRenderer.prototype.setGridData = function(plot) { - // recalculate the grid data - var xp = this._xaxis.series_u2p; - var yp = this._yaxis.series_u2p; - var data = this._plotData; - var pdata = this._prevPlotData; - this.gridData = []; - this._prevGridData = []; - for (var i=0; i<this.data.length; i++) { - if (data[i] != null) { - this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]); - } - if (pdata[i] != null) { - this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), yp.call(this._yaxis, pdata[i][1])]); - } - } - }; - - // Method: makeGridData - // converts any arbitrary data values to grid coordinates and - // returns them. This method exists so that plugins can use a series' - // linerenderer to generate grid data points without overwriting the - // grid data associated with that series. - // Called with scope of a series. - $.jqplot.LineRenderer.prototype.makeGridData = function(data, plot) { - // recalculate the grid data - var xp = this._xaxis.series_u2p; - var yp = this._yaxis.series_u2p; - var gd = []; - var pgd = []; - for (var i=0; i<data.length; i++) { - if (data[i] != null) { - gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]); - } - } - return gd; - }; - - - // called within scope of series. - $.jqplot.LineRenderer.prototype.draw = function(ctx, gd, options) { - var i; - var opts = (options != undefined) ? options : {}; - var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; - var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; - var fill = (opts.fill != undefined) ? opts.fill : this.fill; - var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke; - ctx.save(); - if (gd.length) { - if (showLine) { - // if we fill, we'll have to add points to close the curve. - if (fill) { - if (this.fillToZero) { - // have to break line up into shapes at axis crossings - var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors); - var negativeColor = negativeColors.get(this.index); - if (! this.useNegativeColors) { - negativeColor = opts.fillStyle; - } - var isnegative = false; - var posfs = opts.fillStyle; - - // if stoking line as well as filling, get a copy of line data. - if (fillAndStroke) { - var fasgd = gd.slice(0); - } - // if not stacked, fill down to axis - if (this.index == 0 || !this._stack) { - - var tempgd = []; - var pyzero = this._yaxis.series_u2p(0); - var pxzero = this._xaxis.series_u2p(0); - - if (this.fillAxis == 'y') { - tempgd.push([gd[0][0], pyzero]); - - for (var i=0; i<gd.length-1; i++) { - tempgd.push(gd[i]); - // do we have an axis crossing? - if (this._plotData[i][1] * this._plotData[i+1][1] < 0) { - if (this._plotData[i][1] < 0) { - isnegative = true; - opts.fillStyle = negativeColor; - } - else { - isnegative = false; - opts.fillStyle = posfs; - } - - var xintercept = gd[i][0] + (gd[i+1][0] - gd[i][0]) * (pyzero-gd[i][1])/(gd[i+1][1] - gd[i][1]); - tempgd.push([xintercept, pyzero]); - // now draw this shape and shadow. - if (shadow) { - this.renderer.shadowRenderer.draw(ctx, tempgd, opts); - } - this.renderer.shapeRenderer.draw(ctx, tempgd, opts); - // now empty temp array and continue - tempgd = [[xintercept, pyzero]]; - } - } - if (this._plotData[gd.length-1][1] < 0) { - isnegative = true; - opts.fillStyle = negativeColor; - } - else { - isnegative = false; - opts.fillStyle = posfs; - } - tempgd.push(gd[gd.length-1]); - tempgd.push([gd[gd.length-1][0], pyzero]); - } - // now draw this shape and shadow. - if (shadow) { - this.renderer.shadowRenderer.draw(ctx, tempgd, opts); - } - this.renderer.shapeRenderer.draw(ctx, tempgd, opts); - - - // var gridymin = this._yaxis.series_u2p(0); - // // IE doesn't return new length on unshift - // gd.unshift([gd[0][0], gridymin]); - // len = gd.length; - // gd.push([gd[len - 1][0], gridymin]); - } - // if stacked, fill to line below - else { - var prev = this._prevGridData; - for (var i=prev.length; i>0; i--) { - gd.push(prev[i-1]); - } - if (shadow) { - this.renderer.shadowRenderer.draw(ctx, gd, opts); - } - - this.renderer.shapeRenderer.draw(ctx, gd, opts); - } - } - else { - // if stoking line as well as filling, get a copy of line data. - if (fillAndStroke) { - var fasgd = gd.slice(0); - } - // if not stacked, fill down to axis - if (this.index == 0 || !this._stack) { - // var gridymin = this._yaxis.series_u2p(this._yaxis.min) - this.gridBorderWidth / 2; - var gridymin = ctx.canvas.height; - // IE doesn't return new length on unshift - gd.unshift([gd[0][0], gridymin]); - len = gd.length; - gd.push([gd[len - 1][0], gridymin]); - } - // if stacked, fill to line below - else { - var prev = this._prevGridData; - for (var i=prev.length; i>0; i--) { - gd.push(prev[i-1]); - } - } - if (shadow) { - this.renderer.shadowRenderer.draw(ctx, gd, opts); - } - - this.renderer.shapeRenderer.draw(ctx, gd, opts); - } - if (fillAndStroke) { - var fasopts = $.extend(true, {}, opts, {fill:false, closePath:false}); - this.renderer.shapeRenderer.draw(ctx, fasgd, fasopts); - ////////// - // TODO: figure out some way to do shadows nicely - // if (shadow) { - // this.renderer.shadowRenderer.draw(ctx, fasgd, fasopts); - // } - // now draw the markers - if (this.markerRenderer.show) { - for (i=0; i<fasgd.length; i++) { - this.markerRenderer.draw(fasgd[i][0], fasgd[i][1], ctx, opts.markerOptions); - } - } - } - } - else { - if (shadow) { - this.renderer.shadowRenderer.draw(ctx, gd, opts); - } - - this.renderer.shapeRenderer.draw(ctx, gd, opts); - } - } - - // now draw the markers - if (this.markerRenderer.show && !fill) { - for (i=0; i<gd.length; i++) { - this.markerRenderer.draw(gd[i][0], gd[i][1], ctx, opts.markerOptions); - } - } - } - - ctx.restore(); - }; - - $.jqplot.LineRenderer.prototype.drawShadow = function(ctx, gd, options) { - // This is a no-op, shadows drawn with lines. - }; - - - // class: $.jqplot.LinearAxisRenderer - // The default jqPlot axis renderer, creating a numeric axis. - // The renderer has no additional options beyond the <Axis> object. - $.jqplot.LinearAxisRenderer = function() { - }; - - // called with scope of axis object. - $.jqplot.LinearAxisRenderer.prototype.init = function(options){ - $.extend(true, this, options); - var db = this._dataBounds; - // Go through all the series attached to this axis and find - // the min/max bounds for this axis. - for (var i=0; i<this._series.length; i++) { - var s = this._series[i]; - var d = s._plotData; - - for (var j=0; j<d.length; j++) { - if (this.name == 'xaxis' || this.name == 'x2axis') { - if (d[j][0] < db.min || db.min == null) { - db.min = d[j][0]; - } - if (d[j][0] > db.max || db.max == null) { - db.max = d[j][0]; - } - } - else { - if (d[j][1] < db.min || db.min == null) { - db.min = d[j][1]; - } - if (d[j][1] > db.max || db.max == null) { - db.max = d[j][1]; - } - } - } - } - }; - - // called with scope of axis - $.jqplot.LinearAxisRenderer.prototype.draw = function(ctx) { - if (this.show) { - // populate the axis label and value properties. - // createTicks is a method on the renderer, but - // call it within the scope of the axis. - this.renderer.createTicks.call(this); - // fill a div with axes labels in the right direction. - // Need to pregenerate each axis to get it's bounds and - // position it and the labels correctly on the plot. - var dim=0; - var temp; - - this._elem = $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>'); - - if (this.name == 'xaxis' || this.name == 'x2axis') { - this._elem.width(this._plotDimensions.width); - } - else { - this._elem.height(this._plotDimensions.height); - } - - // create a _label object. - this.labelOptions.axis = this.name; - this._label = new this.labelRenderer(this.labelOptions); - if (this._label.show) { - var elem = this._label.draw(ctx); - elem.appendTo(this._elem); - } - - if (this.showTicks) { - var t = this._ticks; - for (var i=0; i<t.length; i++) { - var tick = t[i]; - if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { - var elem = tick.draw(ctx); - elem.appendTo(this._elem); - } - } - } - } - return this._elem; - }; - - // called with scope of an axis - $.jqplot.LinearAxisRenderer.prototype.reset = function() { - this.min = this._min; - this.max = this._max; - this.tickInterval = this._tickInterval; - this.numberTicks = this._numberTicks; - // this._ticks = this.__ticks; - }; - - // called with scope of axis - $.jqplot.LinearAxisRenderer.prototype.set = function() { - var dim = 0; - var temp; - var w = 0; - var h = 0; - var lshow = (this._label == null) ? false : this._label.show; - if (this.show && this.showTicks) { - var t = this._ticks; - for (var i=0; i<t.length; i++) { - var tick = t[i]; - if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { - if (this.name == 'xaxis' || this.name == 'x2axis') { - temp = tick._elem.outerHeight(true); - } - else { - temp = tick._elem.outerWidth(true); - } - if (temp > dim) { - dim = temp; - } - } - } - - if (lshow) { - w = this._label._elem.outerWidth(true); - h = this._label._elem.outerHeight(true); - } - if (this.name == 'xaxis') { - dim = dim + h; - this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); - } - else if (this.name == 'x2axis') { - dim = dim + h; - this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); - } - else if (this.name == 'yaxis') { - dim = dim + w; - this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { - this._label._elem.css('width', w+'px'); - } - } - else { - dim = dim + w; - this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); - if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { - this._label._elem.css('width', w+'px'); - } - } - } - }; - - // called with scope of axis - $.jqplot.LinearAxisRenderer.prototype.createTicks = function() { - // we're are operating on an axis here - var ticks = this._ticks; - var userTicks = this.ticks; - var name = this.name; - // databounds were set on axis initialization. - var db = this._dataBounds; - var dim, interval; - var min, max; - var pos1, pos2; - var tt, i; - - // if we already have ticks, use them. - // ticks must be in order of increasing value. - - if (userTicks.length) { - // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed - for (i=0; i<userTicks.length; i++){ - var ut = userTicks[i]; - var t = new this.tickRenderer(this.tickOptions); - if (ut.constructor == Array) { - t.value = ut[0]; - t.label = ut[1]; - if (!this.showTicks) { - t.showLabel = false; - t.showMark = false; - } - else if (!this.showTickMarks) { - t.showMark = false; - } - t.setTick(ut[0], this.name); - this._ticks.push(t); - } - - else { - t.value = ut; - if (!this.showTicks) { - t.showLabel = false; - t.showMark = false; - } - else if (!this.showTickMarks) { - t.showMark = false; - } - t.setTick(ut, this.name); - this._ticks.push(t); - } - } - this.numberTicks = userTicks.length; - this.min = this._ticks[0].value; - this.max = this._ticks[this.numberTicks-1].value; - this.tickInterval = (this.max - this.min) / (this.numberTicks - 1); - } - - // we don't have any ticks yet, let's make some! - else { - if (name == 'xaxis' || name == 'x2axis') { - dim = this._plotDimensions.width; - } - else { - dim = this._plotDimensions.height; - } - - // if min, max and number of ticks specified, user can't specify interval. - if (!this.autoscale && this.min != null && this.max != null && this.numberTicks != null) { - this.tickInterval = null; - } - - // if max, min, and interval specified and interval won't fit, ignore interval. - // if (this.min != null && this.max != null && this.tickInterval != null) { - // if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) { - // this.tickInterval = null; - // } - // } - - min = ((this.min != null) ? this.min : db.min); - max = ((this.max != null) ? this.max : db.max); - - // if min and max are same, space them out a bit - if (min == max) { - var adj = 0.05; - if (min > 0) { - adj = Math.max(Math.log(min)/Math.LN10, 0.05); - } - min -= adj; - max += adj; - } - - var range = max - min; - var rmin, rmax; - var temp; - - // autoscale. Can't autoscale if min or max is supplied. - // Will use numberTicks and tickInterval if supplied. Ticks - // across multiple axes may not line up depending on how - // bars are to be plotted. - if (this.autoscale && this.min == null && this.max == null) { - var rrange, ti, margin; - var forceMinZero = false; - var forceZeroLine = false; - var intervals = {min:null, max:null, average:null, stddev:null}; - // if any series are bars, or if any are fill to zero, and if this - // is the axis to fill toward, check to see if we can start axis at zero. - for (var i=0; i<this._series.length; i++) { - var s = this._series[i]; - var faname = (s.fillAxis == 'x') ? s._xaxis.name : s._yaxis.name; - // check to see if this is the fill axis - if (this.name == faname) { - var vals = s._plotValues[s.fillAxis]; - var vmin = vals[0]; - var vmax = vals[0]; - for (var j=1; j<vals.length; j++) { - if (vals[j] < vmin) { - vmin = vals[j]; - } - else if (vals[j] > vmax) { - vmax = vals[j]; - } - } - var dp = (vmax - vmin) / vmax; - // is this sries a bar? - if (s.renderer.constructor == $.jqplot.BarRenderer) { - // if no negative values and could also check range. - if (vmin >= 0 && (s.fillToZero || dp > 0.1)) { - forceMinZero = true; - } - else { - forceMinZero = false; - if (s.fill && s.fillToZero && vmin < 0 && vmax > 0) { - forceZeroLine = true; - } - else { - forceZeroLine = false; - } - } - } - - // if not a bar and filling, use appropriate method. - else if (s.fill) { - if (vmin >= 0 && (s.fillToZero || dp > 0.1)) { - forceMinZero = true; - } - else if (vmin < 0 && vmax > 0 && s.fillToZero) { - forceMinZero = false; - forceZeroLine = true; - } - else { - forceMinZero = false; - forceZeroLine = false; - } - } - - // if not a bar and not filling, only change existing state - // if it doesn't make sense - else if (vmin < 0) { - forceMinZero = false; - } - } - } - - // check if we need make axis min at 0. - if (forceMinZero) { - // compute number of ticks - this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); - this.min = 0; - // what order is this range? - // what tick interval does that give us? - ti = max/(this.numberTicks-1); - temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10))); - if (ti/temp == parseInt(ti/temp, 10)) { - ti += temp; - } - this.tickInterval = Math.ceil(ti/temp) * temp; - this.max = this.tickInterval * (this.numberTicks - 1); - } - - // check if we need to make sure there is a tick at 0. - else if (forceZeroLine) { - // compute number of ticks - this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); - var ntmin = Math.ceil(Math.abs(min)/range*(this.numberTicks-1)); - var ntmax = this.numberTicks - 1 - ntmin; - ti = Math.max(Math.abs(min/ntmin), Math.abs(max/ntmax)); - temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10))); - this.tickInterval = Math.ceil(ti/temp) * temp; - this.max = this.tickInterval * ntmax; - this.min = -this.tickInterval * ntmin; - } - - // if nothing else, do autoscaling which will try to line up ticks across axes. - else { - if (this.numberTicks == null){ - if (this.tickInterval) { - this.numberTicks = 3 + Math.ceil(range / this.tickInterval); - } - else { - this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing); - } - } - - if (this.tickInterval == null) { - // get a tick interval - ti = range/(this.numberTicks - 1); - - if (ti < 1) { - temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10))); - } - else { - temp = 1; - } - this.tickInterval = Math.ceil(ti*temp*this.pad)/temp; - } - else { - temp = 1 / this.tickInterval; - } - - // try to compute a nicer, more even tick interval - // temp = Math.pow(10, Math.floor(Math.log(ti)/Math.LN10)); - // this.tickInterval = Math.ceil(ti/temp) * temp; - rrange = this.tickInterval * (this.numberTicks - 1); - margin = (rrange - range)/2; - - if (this.min == null) { - this.min = Math.floor(temp*(min-margin))/temp; - } - if (this.max == null) { - this.max = this.min + rrange; - } - } - } - - // Use the default algorithm which pads each axis to make the chart - // centered nicely on the grid. - else { - rmin = (this.min != null) ? this.min : min - range*(this.padMin - 1); - rmax = (this.max != null) ? this.max : max + range*(this.padMax - 1); - this.min = rmin; - this.max = rmax; - range = this.max - this.min; - - if (this.numberTicks == null){ - // if tickInterval is specified by user, we will ignore computed maximum. - // max will be equal or greater to fit even # of ticks. - if (this.tickInterval != null) { - this.numberTicks = Math.ceil((this.max - this.min)/this.tickInterval)+1; - this.max = this.min + this.tickInterval*(this.numberTicks-1); - } - else if (dim > 100) { - this.numberTicks = parseInt(3+(dim-100)/75, 10); - } - else { - this.numberTicks = 2; - } - } - - if (this.tickInterval == null) { - this.tickInterval = range / (this.numberTicks-1); - } - } - - for (var i=0; i<this.numberTicks; i++){ - tt = this.min + i * this.tickInterval; - var t = new this.tickRenderer(this.tickOptions); - // var t = new $.jqplot.AxisTickRenderer(this.tickOptions); - if (!this.showTicks) { - t.showLabel = false; - t.showMark = false; - } - else if (!this.showTickMarks) { - t.showMark = false; - } - t.setTick(tt, this.name); - this._ticks.push(t); - } - } - }; - - // called with scope of axis - $.jqplot.LinearAxisRenderer.prototype.pack = function(pos, offsets) { - var ticks = this._ticks; - var max = this.max; - var min = this.min; - var offmax = offsets.max; - var offmin = offsets.min; - var lshow = (this._label == null) ? false : this._label.show; - - for (var p in pos) { - this._elem.css(p, pos[p]); - } - - this._offsets = offsets; - // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. - var pixellength = offmax - offmin; - var unitlength = max - min; - - // point to unit and unit to point conversions references to Plot DOM element top left corner. - this.p2u = function(p){ - return (p - offmin) * unitlength / pixellength + min; - }; - - this.u2p = function(u){ - return (u - min) * pixellength / unitlength + offmin; - }; - - if (this.name == 'xaxis' || this.name == 'x2axis'){ - this.series_u2p = function(u){ - return (u - min) * pixellength / unitlength; - }; - this.series_p2u = function(p){ - return p * unitlength / pixellength + min; - }; - } - - else { - this.series_u2p = function(u){ - return (u - max) * pixellength / unitlength; - }; - this.series_p2u = function(p){ - return p * unitlength / pixellength + max; - }; - } - - if (this.show) { - if (this.name == 'xaxis' || this.name == 'x2axis') { - for (i=0; i<ticks.length; i++) { - var t = ticks[i]; - if (t.show && t.showLabel) { - var shim; - - if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { - // will need to adjust auto positioning based on which axis this is. - var temp = (this.name == 'xaxis') ? 1 : -1; - switch (t.labelPosition) { - case 'auto': - // position at end - if (temp * t.angle < 0) { - shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; - } - // position at start - else { - shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; - } - break; - case 'end': - shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; - break; - case 'start': - shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; - break; - case 'middle': - shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; - break; - default: - shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; - break; - } - } - else { - shim = -t.getWidth()/2; - } - var val = this.u2p(t.value) + shim + 'px'; - t._elem.css('left', val); - t.pack(); - } - } - if (lshow) { - var w = this._label._elem.outerWidth(true); - this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); - if (this.name == 'xaxis') { - this._label._elem.css('bottom', '0px'); - } - else { - this._label._elem.css('top', '0px'); - } - this._label.pack(); - } - } - else { - for (i=0; i<ticks.length; i++) { - var t = ticks[i]; - if (t.show && t.showLabel) { - var shim; - if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { - // will need to adjust auto positioning based on which axis this is. - var temp = (this.name == 'yaxis') ? 1 : -1; - switch (t.labelPosition) { - case 'auto': - // position at end - case 'end': - if (temp * t.angle < 0) { - shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; - } - else { - shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; - } - break; - case 'start': - if (t.angle > 0) { - shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; - } - else { - shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; - } - break; - case 'middle': - // if (t.angle > 0) { - // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; - // } - // else { - // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; - // } - shim = -t.getHeight()/2; - break; - default: - shim = -t.getHeight()/2; - break; - } - } - else { - shim = -t.getHeight()/2; - } - - var val = this.u2p(t.value) + shim + 'px'; - t._elem.css('top', val); - t.pack(); - } - } - if (lshow) { - var h = this._label._elem.outerHeight(true); - this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); - if (this.name == 'yaxis') { - this._label._elem.css('left', '0px'); - } - else { - this._label._elem.css('right', '0px'); - } - this._label.pack(); - } - } - } - }; - - - // class: $.jqplot.MarkerRenderer - // The default jqPlot marker renderer, rendering the points on the line. - $.jqplot.MarkerRenderer = function(options){ - // Group: Properties - - // prop: show - // wether or not to show the marker. - this.show = true; - // prop: style - // One of diamond, circle, square, x, plus, dash, filledDiamond, filledCircle, filledSquare - this.style = 'filledCircle'; - // prop: lineWidth - // size of the line for non-filled markers. - this.lineWidth = 2; - // prop: size - // Size of the marker (diameter or circle, length of edge of square, etc.) - this.size = 9.0; - // prop: color - // color of marker. Will be set to color of series by default on init. - this.color = '#666666'; - // prop: shadow - // wether or not to draw a shadow on the line - this.shadow = true; - // prop: shadowAngle - // Shadow angle in degrees - this.shadowAngle = 45; - // prop: shadowOffset - // Shadow offset from line in pixels - this.shadowOffset = 1; - // prop: shadowDepth - // Number of times shadow is stroked, each stroke offset shadowOffset from the last. - this.shadowDepth = 3; - // prop: shadowAlpha - // Alpha channel transparency of shadow. 0 = transparent. - this.shadowAlpha = '0.07'; - // prop: shadowRenderer - // Renderer that will draws the shadows on the marker. - this.shadowRenderer = new $.jqplot.ShadowRenderer(); - // prop: shapeRenderer - // Renderer that will draw the marker. - this.shapeRenderer = new $.jqplot.ShapeRenderer(); - - $.extend(true, this, options); - }; - - $.jqplot.MarkerRenderer.prototype.init = function(options) { - $.extend(true, this, options); - var sdopt = {angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, lineWidth:this.lineWidth, depth:this.shadowDepth, closePath:true}; - if (this.style.indexOf('filled') != -1) { - sdopt.fill = true; - } - if (this.style.indexOf('ircle') != -1) { - sdopt.isarc = true; - sdopt.closePath = false; - } - this.shadowRenderer.init(sdopt); - - var shopt = {fill:false, isarc:false, strokeStyle:this.color, fillStyle:this.color, lineWidth:this.lineWidth, closePath:true}; - if (this.style.indexOf('filled') != -1) { - shopt.fill = true; - } - if (this.style.indexOf('ircle') != -1) { - shopt.isarc = true; - shopt.closePath = false; - } - this.shapeRenderer.init(shopt); - }; - - $.jqplot.MarkerRenderer.prototype.drawDiamond = function(x, y, ctx, fill, options) { - var stretch = 1.2; - var dx = this.size/2/stretch; - var dy = this.size/2*stretch; - var points = [[x-dx, y], [x, y+dy], [x+dx, y], [x, y-dy]]; - if (this.shadow) { - this.shadowRenderer.draw(ctx, points); - } - this.shapeRenderer.draw(ctx, points, options); - - ctx.restore(); - }; - - $.jqplot.MarkerRenderer.prototype.drawPlus = function(x, y, ctx, fill, options) { - var stretch = 1.0; - var dx = this.size/2*stretch; - var dy = this.size/2*stretch; - var points1 = [[x, y-dy], [x, y+dy]]; - var points2 = [[x+dx, y], [x-dx, y]]; - var opts = $.extend(true, {}, this.options, {closePath:false}); - if (this.shadow) { - this.shadowRenderer.draw(ctx, points1, {closePath:false}); - this.shadowRenderer.draw(ctx, points2, {closePath:false}); - } - this.shapeRenderer.draw(ctx, points1, opts); - this.shapeRenderer.draw(ctx, points2, opts); - - ctx.restore(); - }; - - $.jqplot.MarkerRenderer.prototype.drawX = function(x, y, ctx, fill, options) { - var stretch = 1.0; - var dx = this.size/2*stretch; - var dy = this.size/2*stretch; - var opts = $.extend(true, {}, this.options, {closePath:false}); - var points1 = [[x-dx, y-dy], [x+dx, y+dy]]; - var points2 = [[x-dx, y+dy], [x+dx, y-dy]]; - if (this.shadow) { - this.shadowRenderer.draw(ctx, points1, {closePath:false}); - this.shadowRenderer.draw(ctx, points2, {closePath:false}); - } - this.shapeRenderer.draw(ctx, points1, opts); - this.shapeRenderer.draw(ctx, points2, opts); - - ctx.restore(); - }; - - $.jqplot.MarkerRenderer.prototype.drawDash = function(x, y, ctx, fill, options) { - var stretch = 1.0; - var dx = this.size/2*stretch; - var dy = this.size/2*stretch; - var points = [[x-dx, y], [x+dx, y]]; - if (this.shadow) { - this.shadowRenderer.draw(ctx, points); - } - this.shapeRenderer.draw(ctx, points, options); - - ctx.restore(); - }; - - $.jqplot.MarkerRenderer.prototype.drawSquare = function(x, y, ctx, fill, options) { - var stretch = 1.0; - var dx = this.size/2/stretch; - var dy = this.size/2*stretch; - var points = [[x-dx, y-dy], [x-dx, y+dy], [x+dx, y+dy], [x+dx, y-dy]]; - if (this.shadow) { - this.shadowRenderer.draw(ctx, points); - } - this.shapeRenderer.draw(ctx, points, options); - - ctx.restore(); - }; - - $.jqplot.MarkerRenderer.prototype.drawCircle = function(x, y, ctx, fill, options) { - var radius = this.size/2; - var end = 2*Math.PI; - var points = [x, y, radius, 0, end, true]; - if (this.shadow) { - this.shadowRenderer.draw(ctx, points); - } - this.shapeRenderer.draw(ctx, points, options); - - ctx.restore(); - }; - - $.jqplot.MarkerRenderer.prototype.draw = function(x, y, ctx, options) { - options = options || {}; - switch (this.style) { - case 'diamond': - this.drawDiamond(x,y,ctx, false, options); - break; - case 'filledDiamond': - this.drawDiamond(x,y,ctx, true, options); - break; - case 'circle': - this.drawCircle(x,y,ctx, false, options); - break; - case 'filledCircle': - this.drawCircle(x,y,ctx, true, options); - break; - case 'square': - this.drawSquare(x,y,ctx, false, options); - break; - case 'filledSquare': - this.drawSquare(x,y,ctx, true, options); - break; - case 'x': - this.drawX(x,y,ctx, true, options); - break; - case 'plus': - this.drawPlus(x,y,ctx, true, options); - break; - case 'dash': - this.drawDash(x,y,ctx, true, options); - break; - default: - this.drawDiamond(x,y,ctx, false, options); - break; - } - }; - - // class: $.jqplot.shadowRenderer - // The default jqPlot shadow renderer, rendering shadows behind shapes. - $.jqplot.ShadowRenderer = function(options){ - // Group: Properties - - // prop: angle - // Angle of the shadow in degrees. Measured counter-clockwise from the x axis. - this.angle = 45; - // prop: offset - // Pixel offset at the given shadow angle of each shadow stroke from the last stroke. - this.offset = 1; - // prop: alpha - // alpha transparency of shadow stroke. - this.alpha = 0.07; - // prop: lineWidth - // width of the shadow line stroke. - this.lineWidth = 1.5; - // prop: lineJoin - // How line segments of the shadow are joined. - this.lineJoin = 'miter'; - // prop: lineCap - // how ends of the shadow line are rendered. - this.lineCap = 'round'; - // prop; closePath - // whether line path segment is closed upon itself. - this.closePath = false; - // prop: fill - // whether to fill the shape. - this.fill = false; - // prop: depth - // how many times the shadow is stroked. Each stroke will be offset by offset at angle degrees. - this.depth = 3; - // prop: isarc - // wether the shadow is an arc or not. - this.isarc = false; - - $.extend(true, this, options); - }; - - $.jqplot.ShadowRenderer.prototype.init = function(options) { - $.extend(true, this, options); - }; - - // function: draw - // draws an transparent black (i.e. gray) shadow. - // - // ctx - canvas drawing context - // points - array of points or [x, y, radius, start angle (rad), end angle (rad)] - $.jqplot.ShadowRenderer.prototype.draw = function(ctx, points, options) { - ctx.save(); - var opts = (options != null) ? options : {}; - var fill = (opts.fill != null) ? opts.fill : this.fill; - var closePath = (opts.closePath != null) ? opts.closePath : this.closePath; - var offset = (opts.offset != null) ? opts.offset : this.offset; - var alpha = (opts.alpha != null) ? opts.alpha : this.alpha; - var depth = (opts.depth != null) ? opts.depth : this.depth; - ctx.lineWidth = (opts.lineWidth != null) ? opts.lineWidth : this.lineWidth; - ctx.lineJoin = (opts.lineJoin != null) ? opts.lineJoin : this.lineJoin; - ctx.lineCap = (opts.lineCap != null) ? opts.lineCap : this.lineCap; - ctx.strokeStyle = 'rgba(0,0,0,'+alpha+')'; - ctx.fillStyle = 'rgba(0,0,0,'+alpha+')'; - for (var j=0; j<depth; j++) { - ctx.translate(Math.cos(this.angle*Math.PI/180)*offset, Math.sin(this.angle*Math.PI/180)*offset); - ctx.beginPath(); - if (this.isarc) { - ctx.arc(points[0], points[1], points[2], points[3], points[4], true); - } - else { - ctx.moveTo(points[0][0], points[0][1]); - for (var i=1; i<points.length; i++) { - ctx.lineTo(points[i][0], points[i][1]); - } - - } - if (closePath) { - ctx.closePath(); - } - if (fill) { - ctx.fill(); - } - else { - ctx.stroke(); - } - } - ctx.restore(); - }; - - // class: $.jqplot.shapeRenderer - // The default jqPlot shape renderer. Given a set of points will - // plot them and either stroke a line (fill = false) or fill them (fill = true). - // If a filled shape is desired, closePath = true must also be set to close - // the shape. - $.jqplot.ShapeRenderer = function(options){ - - this.lineWidth = 1.5; - // prop: lineJoin - // How line segments of the shadow are joined. - this.lineJoin = 'miter'; - // prop: lineCap - // how ends of the shadow line are rendered. - this.lineCap = 'round'; - // prop; closePath - // whether line path segment is closed upon itself. - this.closePath = false; - // prop: fill - // whether to fill the shape. - this.fill = false; - // prop: isarc - // wether the shadow is an arc or not. - this.isarc = false; - // prop: fillRect - // true to draw shape as a filled rectangle. - this.fillRect = false; - // prop: strokeRect - // true to draw shape as a stroked rectangle. - this.strokeRect = false; - // prop: clearRect - // true to cear a rectangle. - this.clearRect = false; - // prop: strokeStyle - // css color spec for the stoke style - this.strokeStyle = '#999999'; - // prop: fillStyle - // css color spec for the fill style. - this.fillStyle = '#999999'; - - $.extend(true, this, options); - }; - - $.jqplot.ShapeRenderer.prototype.init = function(options) { - $.extend(true, this, options); - }; - - // function: draw - // draws the shape. - // - // ctx - canvas drawing context - // points - array of points for shapes or - // [x, y, width, height] for rectangles or - // [x, y, radius, start angle (rad), end angle (rad)] for circles and arcs. - $.jqplot.ShapeRenderer.prototype.draw = function(ctx, points, options) { - ctx.save(); - var opts = (options != null) ? options : {}; - var fill = (opts.fill != null) ? opts.fill : this.fill; - var closePath = (opts.closePath != null) ? opts.closePath : this.closePath; - var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect; - var strokeRect = (opts.strokeRect != null) ? opts.strokeRect : this.strokeRect; - var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect; - var isarc = (opts.isarc != null) ? opts.isarc : this.isarc; - ctx.lineWidth = opts.lineWidth || this.lineWidth; - ctx.lineJoin = opts.lineJoing || this.lineJoin; - ctx.lineCap = opts.lineCap || this.lineCap; - ctx.strokeStyle = (opts.strokeStyle || opts.color) || this.strokeStyle; - ctx.fillStyle = opts.fillStyle || this.fillStyle; - ctx.beginPath(); - if (isarc) { - ctx.arc(points[0], points[1], points[2], points[3], points[4], true); - if (closePath) { - ctx.closePath(); - } - if (fill) { - ctx.fill(); - } - else { - ctx.stroke(); - } - ctx.restore(); - return; - } - else if (clearRect) { - ctx.clearRect(points[0], points[1], points[2], points[3]); - ctx.restore(); - return; - } - else if (fillRect || strokeRect) { - if (fillRect) { - ctx.fillRect(points[0], points[1], points[2], points[3]); - } - if (strokeRect) { - ctx.strokeRect(points[0], points[1], points[2], points[3]); - ctx.restore(); - return; - } - } - else { - ctx.moveTo(points[0][0], points[0][1]); - for (var i=1; i<points.length; i++) { - ctx.lineTo(points[i][0], points[i][1]); - } - if (closePath) { - ctx.closePath(); - } - if (fill) { - ctx.fill(); - } - else { - ctx.stroke(); - } - } - ctx.restore(); - }; - - // class $.jqplot.TableLegendRenderer - // The default legend renderer for jqPlot, this class has no options beyond the <Legend> class. - $.jqplot.TableLegendRenderer = function(){ - // - }; - - $.jqplot.TableLegendRenderer.prototype.init = function(options) { - $.extend(true, this, options); - }; - - $.jqplot.TableLegendRenderer.prototype.addrow = function (label, color, pad) { - var rs = (pad) ? this.rowSpacing : '0'; - var tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); - $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ - '<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ - '</div></td>').appendTo(tr); - var elem = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); - elem.appendTo(tr); - if (this.escapeHtml) { - elem.text(label); - } - else { - elem.html(label); - } - }; - - // called with scope of legend - $.jqplot.TableLegendRenderer.prototype.draw = function() { - var legend = this; - if (this.show) { - var series = this._series; - // make a table. one line label per row. - var ss = 'position:absolute;'; - ss += (this.background) ? 'background:'+this.background+';' : ''; - ss += (this.border) ? 'border:'+this.border+';' : ''; - ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; - ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; - ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; - this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); - - var pad = false; - for (var i = 0; i< series.length; i++) { - s = series[i]; - if (s.show && s.showLabel) { - var lt = s.label.toString(); - if (lt) { - var color = s.color; - if (s._stack && !s.fill) { - color = ''; - } - this.renderer.addrow.call(this, lt, color, pad); - pad = true; - } - // let plugins add more rows to legend. Used by trend line plugin. - for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) { - var item = $.jqplot.addLegendRowHooks[j].call(this, s); - if (item) { - this.renderer.addrow.call(this, item.label, item.color, pad); - pad = true; - } - } - } - } - } - return this._elem; - }; - - $.jqplot.TableLegendRenderer.prototype.pack = function(offsets) { - if (this.show) { - // fake a grid for positioning - var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom}; - switch (this.location) { - case 'nw': - var a = grid._left + this.xoffset; - var b = grid._top + this.yoffset; - this._elem.css('left', a); - this._elem.css('top', b); - break; - case 'n': - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; - var b = grid._top + this.yoffset; - this._elem.css('left', a); - this._elem.css('top', b); - break; - case 'ne': - var a = offsets.right + this.xoffset; - var b = grid._top + this.yoffset; - this._elem.css({right:a, top:b}); - break; - case 'e': - var a = offsets.right + this.xoffset; - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; - this._elem.css({right:a, top:b}); - break; - case 'se': - var a = offsets.right + this.xoffset; - var b = offsets.bottom + this.yoffset; - this._elem.css({right:a, bottom:b}); - break; - case 's': - var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; - var b = offsets.bottom + this.yoffset; - this._elem.css({left:a, bottom:b}); - break; - case 'sw': - var a = grid._left + this.xoffset; - var b = offsets.bottom + this.yoffset; - this._elem.css({left:a, bottom:b}); - break; - case 'w': - var a = grid._left + this.xoffset; - var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; - this._elem.css({left:a, top:b}); - break; - default: // same as 'se' - var a = grid._right - this.xoffset; - var b = grid._bottom + this.yoffset; - this._elem.css({right:a, bottom:b}); - break; - } - } - }; - - /** - * JavaScript printf/sprintf functions. - * - * This code is unrestricted: you are free to use it however you like. - * - * The functions should work as expected, performing left or right alignment, - * truncating strings, outputting numbers with a required precision etc. - * - * For complex cases, these functions follow the Perl implementations of - * (s)printf, allowing arguments to be passed out-of-order, and to set the - * precision or length of the output based on arguments instead of fixed - * numbers. - * - * See http://perldoc.perl.org/functions/sprintf.html for more information. - * - * Implemented: - * - zero and space-padding - * - right and left-alignment, - * - base X prefix (binary, octal and hex) - * - positive number prefix - * - (minimum) width - * - precision / truncation / maximum width - * - out of order arguments - * - * Not implemented (yet): - * - vector flag - * - size (bytes, words, long-words etc.) - * - * Will not implement: - * - %n or %p (no pass-by-reference in JavaScript) - * - * @version 2007.04.27 - * @author Ash Searle - */ - - /** - * @Modifications 2009.05.26 - * @author Chris Leonello - * - * Added %p %P specifier - * Acts like %g or %G but will not add more significant digits to the output than present in the input. - * Example: - * Format: '%.3p', Input: 0.012, Output: 0.012 - * Format: '%.3g', Input: 0.012, Output: 0.0120 - * Format: '%.4p', Input: 12.0, Output: 12.0 - * Format: '%.4g', Input: 12.0, Output: 12.00 - * Format: '%.4p', Input: 4.321e-5, Output: 4.321e-5 - * Format: '%.4g', Input: 4.321e-5, Output: 4.3210e-5 - */ - $.jqplot.sprintf = function() { - function pad(str, len, chr, leftJustify) { - var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr); - return leftJustify ? str + padding : padding + str; - - } - - function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace) { - var diff = minWidth - value.length; - if (diff > 0) { - var spchar = ' '; - if (htmlSpace) { spchar = ' '; } - if (leftJustify || !zeroPad) { - value = pad(value, minWidth, spchar, leftJustify); - } else { - value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length); - } - } - return value; - } - - function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad, htmlSpace) { - // Note: casts negative numbers to positive ones - var number = value >>> 0; - prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || ''; - value = prefix + pad(number.toString(base), precision || 0, '0', false); - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); - } - - function formatString(value, leftJustify, minWidth, precision, zeroPad, htmlSpace) { - if (precision != null) { - value = value.slice(0, precision); - } - return justify(value, '', leftJustify, minWidth, zeroPad, htmlSpace); - } - - var a = arguments, i = 0, format = a[i++]; - - return format.replace($.jqplot.sprintf.regex, function(substring, valueIndex, flags, minWidth, _, precision, type) { - if (substring == '%%') { return '%'; } - - // parse flags - var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, htmlSpace = false; - for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) { - case ' ': positivePrefix = ' '; break; - case '+': positivePrefix = '+'; break; - case '-': leftJustify = true; break; - case '0': zeroPad = true; break; - case '#': prefixBaseX = true; break; - case '&': htmlSpace = true; break; - } - - // parameters may be null, undefined, empty-string or real valued - // we want to ignore null, undefined and empty-string values - - if (!minWidth) { - minWidth = 0; - } - else if (minWidth == '*') { - minWidth = +a[i++]; - } - else if (minWidth.charAt(0) == '*') { - minWidth = +a[minWidth.slice(1, -1)]; - } - else { - minWidth = +minWidth; - } - - // Note: undocumented perl feature: - if (minWidth < 0) { - minWidth = -minWidth; - leftJustify = true; - } - - if (!isFinite(minWidth)) { - throw new Error('$.jqplot.sprintf: (minimum-)width must be finite'); - } - - if (!precision) { - precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0); - } - else if (precision == '*') { - precision = +a[i++]; - } - else if (precision.charAt(0) == '*') { - precision = +a[precision.slice(1, -1)]; - } - else { - precision = +precision; - } - - // grab value using valueIndex if required? - var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++]; - - switch (type) { - case 's': { - if (value == null) { - return ''; - } - return formatString(String(value), leftJustify, minWidth, precision, zeroPad, htmlSpace); - } - case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad, htmlSpace); - case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad,htmlSpace); - case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); - case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); - case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace).toUpperCase(); - case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); - case 'i': - case 'd': { - var number = parseInt(+value, 10); - if (isNaN(number)) { - return ''; - } - var prefix = number < 0 ? '-' : positivePrefix; - value = prefix + pad(String(Math.abs(number)), precision, '0', false); - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); - } - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - { - var number = +value; - if (isNaN(number)) { - return ''; - } - var prefix = number < 0 ? '-' : positivePrefix; - var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())]; - var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2]; - value = prefix + Math.abs(number)[method](precision); - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform](); - } - case 'p': - case 'P': - { - // make sure number is a number - var number = +value; - if (isNaN(number)) { - return ''; - } - var prefix = number < 0 ? '-' : positivePrefix; - - var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/); - var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length; - var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0; - - if (Math.abs(number) < 1) { - if (sd + zeros <= precision) { - value = prefix + Math.abs(number).toPrecision(sd); - } - else { - if (sd <= precision - 1) { - value = prefix + Math.abs(number).toExponential(sd-1); - } - else { - value = prefix + Math.abs(number).toExponential(precision-1); - } - } - } - else { - var prec = (sd <= precision) ? sd : precision; - value = prefix + Math.abs(number).toPrecision(prec); - } - var textTransform = ['toString', 'toUpperCase']['pP'.indexOf(type) % 2]; - return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform](); - } - case 'n': return ''; - default: return substring; - } - }); - }; - - $.jqplot.sprintf.regex = /%%|%(\d+\$)?([-+#0& ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g; - -})(jQuery); \ No newline at end of file diff --git a/frontend/javascripts/jqplot/optionsTutorial.txt b/frontend/javascripts/jqplot/optionsTutorial.txt deleted file mode 100644 index 3e68825..0000000 --- a/frontend/javascripts/jqplot/optionsTutorial.txt +++ /dev/null @@ -1,239 +0,0 @@ -Title: Options Tutorial - -This document will help you understand how jqPlot's options -relate to the API documentation and the jqPlot object -itself. For a listing of options available to jqPlot, -see <jqPlot Options> in the jqPlotOptions.txt file. - -The key to effectively using jqPlot is understanding jqPlot's -options. The online documentation is API documentation. While -it explains what attributes and methods various objects posses, -it doesn't explain how to use or set those attributes through -options. This tutorial will help explain that. - -Lets assume you are creating a plot -like this: - -> chart = $.jqplot('chart', dataSeries, optionsObj); - -First, note that you shouldn't try to directly set attributes on the -"chart" object (like chart.grid.shadow) after your call to $.jqplot(). -At best this won't do anything **(see below). You should pass options in via -the "optionsObj". - -the optionsObj really represents the plot object (jqPlot object, not -to be confused with the $.jqplot function which will create a jqPlot -object). Attributes you specify on that object will be merged with -attributes in the jqPlot object. The axes, legend, series, etc. are -attributes on the jqPlot object. The jqPlot/optionsObj object looks -something like (only some attributes shown): - -> jqPlot-| -> |-seriesColors -> |-textColor -> |-fontFamily -> |-fontSize -> |-stackSeries -> |-series(Array)-| -> | |-Series1-| -> | | |-lineWidth -> | | |-shadow -> | | |-showLine -> | | |-showMarker -> | | |-color -> | |-Series2... -> | |-... -> | |-SeriesN -> | -> |-grid(Object)-| -> | |-drawGridLines -> | |-background -> | |-borderColor -> | |-borderWidth -> | |-shadow -> | -> |-title(Object)-| -> | |-text -> | |-show -> | |-fontFamily -> | |-fontSize -> | |-textAlign -> | |-textColor -> | -> |-axes(Object)-| -> | |-xais-| -> | | |-min -> | | |-max -> | | |-numberTicks -> | | |-showTicks -> | | |-showTickMarks -> | | |-pad -> | -> | ... and so on - -The optionsObj should follow the same construction as if it were a -jqPlot object (with some exceptions/shortcuts I'll mention in a -moment). So generally, when you see something like -"this.drawGridLines" in the grid properties in the docs, just replace -"this" with "grid" in your options object. So it becomes -optionsObj.grid.drawGridLines. Do likewise with the other objects in -the plot, replacing "this", with the respective attribute on the plot -like "legend" or "title". Series and Axes are handled a little -different, because series is an array and axes has 4 distinct children -"xaxis", "yaxis", "x2axis" and "y2axis". - -So, to remove the shadow from the grid and change the grid border size -you would do: - -> optionObj = {grid:{shadow:false, borderWidth:9.0}}; - -To do the same as above but also make all the text in the plot red you -would do: - -> optionObj = { -> textColor:"#ff0000", -> grid:{shadow:false, borderWidth:9.0} -> } - -Here is a more deeply nested example. Say you want to specify a min -and max on your y axis and use a specific color for your second -series. That would look like: - -> optionsObj = { -> axes:{yaxis:{min:5, max:230}}, -> series:[{},{color:"#33ff66"}] -> } - -Note that series options are an array in order of the series data you -sent in to your plot. To get to the second series, you have to put an -object (even if empty) in place of the first series. - -There is a handy shortcut to assign options to all axes or all series -at one go. Use axesDefaults and seriesDefaults. So, if you wanted -both x and y axes to start at 0 and you wanted all series to not show -markers, you could do: - -> optionsObj = {axesDefaults:{min:0}, seriesDefaults:{showMarker:false}} - -Another shortcut is for the plot title. Normally, you would assign -options to the title as an object. If you specify a title option as a -string, it will assign that to the title.text property automatically. -So these two are equivalent: - -> optionsObj = {title:{text:"My Plot"}} - -and - -> optionsObj = {title:"My Plot"} - -Where things need more explaination is with renderers, plugins and -their options. Briefly, what's renderer, what's a plugin. - -A renderer is an object that is used to draw something and gets -attached to an existing object in the plot in order to draw it. A -plugin does more than just provide drawing functionality to an -object. It will do more like calculate a trend line, change the -cursor, provide event driven functionality, etc. I consider renderers -plugins, but plugins don't have to be renderers. - -So, how do you use renderers, plugins, and specify their options? -Some common renderes are for bar charts and category axes. If you -want to render your series as a bar chart with each set of bars -showing up in a category on the x axis, you do: - -> optionsObj = { -> seriesDefaults:{renderer:$.jqplot.BarRenderer}, -> axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}} -> } - -This replaces the default renderer used for all series in the plot -with a bar renderer and the x axis default renderer (but not any other -axis) with a category renderer. - -Now, how would I assign options to those renderers? The renderer's -attributes may not be present in the pre-existing jqPlot object, they -may be specific to the renderer. This is done through the -"rendererOptions" option on the appropriate object. So, if I wanted my -bars to be 25 pixels wide, I would do: - - -> optionsObj = { -> seriesDefaults:{ -> renderer:$.jqplot.BarRenderer}, -> rendererOptions:{ -> barWidth:25 -> }, -> axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}} -> } - -Again, this is using the "seriesDefaults" option, which will apply -options to all series in the plot. You could do the same on any -particular series in the plot through the "series" options array. - -Plugins are free to add their own options. For example, the -highlighter plugin has it's own set of options that are unique to it. -As a result, it responds to options placed in the "highlighter" -attribute of your options object. So, if I wanted to change the -highlighter tooltip to fade in and out slowly and be positioned -directly above the point I'm highlighting: - -> optionsObj = { -> highlighter:{tooltipFadeSpeed:'slow', tooltipLocation:'n'} -> } - -Other plugins, like dragable and trendlines, add their options in with -the series. This is because both of those plugins can have different -options for different series in the plot. So, if you wanted to specify the -color of the dragable and constrain it to drag only on the x axis as well -as specify the color of the trend line you could do: - -> series:[{ -> dragable: { -> color: '#ff3366', -> constrainTo: 'x' -> }, -> trendline: { -> color: '#cccccc' -> } -> }] - -This would apply those options to the first series only. If you had 2 series -and wanted to turn off dragging and trend lines on the second series, you could do: - -> series:[{ -> dragable: { -> color: '#ff3366', -> constrainTo: 'x' -> }, -> trendline: { -> color: '#cccccc' -> } -> }, { -> isDragable: false, -> trendline:{ -> show: false -> } -> }] - -Note, series dragability is turned off with the "isDragable" option directly on -the series itself, not with a suboption of "dragable". This may be improved -in the future. - -I hope this is helpful. -A few key points to remember: - -- When you see "this" in the api docs, you generally replace it with -the name of the object (in lowercase) you are looking at in your -options object. -- seriesDefaults and axesDefaults are convenient shortcuts. -- to assign options to a renderer, generally use the "rendererOptions" -- plugins may add their own options attribute, like "highlighter" or -"cursor". - -** Note: you can set attributes after the plot is created (like -plot.grid.shadow = false), but you'll have to issue the appropriate -calls to possibly reinitialize and redraw the plot. jqPlot can -definitely handle this to change the plot after creation (this is how -the dragable plugin updates the plot data and the trend line plugin -recomputes itself when data changes). This hasn't been documented -yet, however. \ No newline at end of file diff --git a/frontend/javascripts/jqplot/usage.txt b/frontend/javascripts/jqplot/usage.txt deleted file mode 100644 index fbef501..0000000 --- a/frontend/javascripts/jqplot/usage.txt +++ /dev/null @@ -1,119 +0,0 @@ -Title: jqPlot Usage - -Usage Documentation: - -Introduction: - -jqPlot is a jQuery plugin to generate pure client-side javascript charts in your web pages. - -The jqPlot home page is at <http://www.jqplot.com/>. - -The project page and downloads are at <http://www.bitbucket.org/cleonello/jqplot/>. - -Below are a few examples to demonstrate jqPlot usage. These plots are shown as static images. -Many more examples of dynamically rendered plots can be seen on the test and examples pages here: <../../tests/>. - -Include the Files: - -jqPlot requires jQuery (tested with 1.3.2 or better). jQuery 1.3.2 is included in the distribution. -To use jqPlot include jquery, the jqPlot jQuery plugin, jqPlot css file and optionally the excanvas -script for IE support in your web page: - -> <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]--> -> <script language="javascript" type="text/javascript" src="jquery-1.3.2.min.js"></script> -> <script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script> -> <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" /> - -Add a plot container: - -Add a container (target) to your web page where you want your plot to show up. -Be sure to give your target a width and a height: - -> <div id="chartdiv" style="height:400px;width:300px; "></div> - -Create a plot: - -Then, create the actual plot by calling the -$.jqplot plugin with the id of your target and some data: - -> $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]); - -Which will produce a -chart like: - -(see images/basicline.png) - -Plot Options: - -You can customize the plot by passing options to the $.jqplot function. Options are described in -<jqPlot Options> in the jqPlotOptions.txt file. An example of options usage: - -> $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]], -> { title:'Exponential Line', -> axes:{yaxis:{min:-10, max:240}}, -> series:[{color:'#5FAB78'}] -> }); - -Which will produce -a plot like: - -(see images/basicoptions.png) - -Using Plugins: - -You can use jqPlot plugins (that is, plugins to the jqPlot plugin) by including them in your html -after you include the jqPlot plugin. Here is how to include the log axis plugin: - -> <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" /> -> <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]--> -> <script language="javascript" type="text/javascript" src="jquery-1.3.2.min.js"></script> -> <script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script> -> <script language="javascript" type="text/javascript" src="jqplot.logAxisRenderer.js"></script> - -Here is a the same $.jqplot call -but with a log y axis: - -> $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]], -> { title:'Exponential Line', -> axes:{yaxis:{renderer: $.jqplot.LogAxisRenderer}}, -> series:[{color:'#5FAB78'}] -> }); - -Which produces -a plot like: - -(see images/basiclogaxis.png) - -You can further customize with options specific -to the log axis plugin: - -> $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]], -> { title:'Exponential Line', -> axes:{yaxis:{renderer: $.jqplot.LogAxisRenderer, tickDistribution:'power'}}, -> series:[{color:'#5FAB78'}] -> }); - -Which makes a -plot like: - -(see images/basiclogoptions.png) - -For a full list of options, see <jqPlot Options> in the jqPlotOptions.txt file. - -You can add as many plugins as you wish. Order is generally not important. -Some plugins, like the highlighter plugin which highlights data points near the -mouse, don't need any extra options or setup to function. Highlighter does have -additional options which the user can set. - -Other plugins, the barRenderer for example, provide functionality the must be specified -in the chart options object. To render a series as a bar graph with the bar renderer, -you would first include the plugin after jqPlot: - -> <script language="javascript" type="text/javascript" src="plugins/jqplot.barRenderer.min.js"></script> - -Then you would create -a chart like: - -> $.jqplot('chartdiv', [[34.53, 56.32, 25.1, 18.6]], series:[{renderer:$.jqplot.BarRenderer}]); - -Here the default LineRenderer is replaced by a BarRenderer to generate a bar graph for the first (an only) series. \ No newline at end of file diff --git a/frontend/javascripts/jquery-extensions.js b/frontend/javascripts/jquery-extensions.js index 9aec604..a4957f9 100644 --- a/frontend/javascripts/jquery-extensions.js +++ b/frontend/javascripts/jquery-extensions.js @@ -85,7 +85,8 @@ $.extend({ var path = options.path ? '; path=' + (options.path) : ''; var domain = options.domain ? '; domain=' + (options.domain) : ''; var secure = options.secure ? '; secure' : ''; - document.cookie = [ name, '=', encodeURIComponent(value), expires, path, domain, secure ].join(''); + + document.cookie = name + '=' + encodeURIComponent(value) + expires + path + domain + secure; }, getCookie: function(name) { var value = null; diff --git a/frontend/javascripts/script.js b/frontend/javascripts/script.js index 98e4eb7..c9313ce 100644 --- a/frontend/javascripts/script.js +++ b/frontend/javascripts/script.js @@ -25,80 +25,81 @@ * along with volkszaehler.org. If not, see <http://www.gnu.org/licenses/>. */ -/* - * Constants & settings - */ -var backendUrl = '../backend/index.php'; -var tuples = 300; -var colors = ['#83CAFF', '#7E0021', '#579D1C', '#FFD320', '#FF420E', '#004586', '#0084D1', '#C5000B', '#FF950E', '#4B1F6F', '#AECF00', '#314004']; -var jqOptions = { - series: [], - cursor: { - zoom: true, - showTooltip: true, - constrainZoomTo: 'x' - }, - seriesDefaults: { - lineWidth: 1, - showMarker: true, - showLine: false, - markerOptions: { - style: 'dash', - shadow: false, - size: 2 - }, - trendline: { - shadow: false - } - }, - axes: { - yaxis: { - autoscale: true, - min: 0, - label: 'Leistung (Watt)', - tickOptions: { - formatString: '%.3f' +// volkszaehler.org object +// holds all data and options for the frontend +var vz = { + // storing entities + entities: new Array, + uuids: new Array, + + // parameter for json server + to: new Date().getTime(), + + //parameter for json server (last 24 hours) + from: new Date().getTime() - 24*60*60*1000, + + options: { + backendUrl: '../backend/index.php', + tuples: 300, + plot: { + series: [], + seriesColors: ['#83CAFF', '#7E0021', '#579D1C', '#FFD320', '#FF420E', '#004586', '#0084D1', '#C5000B', '#FF950E', '#4B1F6F', '#AECF00', '#314004'], + cursor: { + zoom: true, + showTooltip: true, + constrainZoomTo: 'x', + showVerticalLine: true }, - labelRenderer: $.jqplot.CanvasAxisLabelRenderer - }, - xaxis: { - autoscale: true, - min: myWindowStart, - max: myWindowEnd, - tickOptions: { - formatString: '%d.%m.%y %H:%M', - angle: -35 + seriesDefaults: { + lineWidth: 1, + showMarker: true, + showLine: false, + markerOptions: { + style: 'dash', + shadow: false, + size: 2 + }, + trendline: { + show: true, + shadow: false + } }, - pad: 1, - renderer: $.jqplot.DateAxisRenderer, - rendererOptions: { - tickRenderer: $.jqplot.CanvasAxisTickRenderer + axes: { + yaxis: { + autoscale: true, + label: 'Leistung (Watt)', + tickOptions: { + formatString: '%.3f' + }, + labelRenderer: $.jqplot.CanvasAxisLabelRenderer + }, + xaxis: { + autoscale: true, + tickOptions: { + formatString: '%d.%m.%y %H:%M', + angle: -35 + }, + pad: 1, + renderer: $.jqplot.DateAxisRenderer, + rendererOptions: { + tickRenderer: $.jqplot.CanvasAxisTickRenderer + } + } } } } }; -// storing entities -var entities = new Array; -var uuids = new Array; - -// windowEnd parameter for json server -var myWindowEnd = new Date().getTime(); - -// windowStart parameter for json server (last 24 hours) -var myWindowStart = myWindowEnd - 24*60*60*1000; - // executed on document loaded complete // this is where it all starts... $(document).ready(function() { // parse uuids from cookie - uuids = getUUIDs(); + vz.uuids = getUUIDs(); // add optional uuid from url if($.getUrlVar('uuid')) { addUUID($.getUrlVar('uuid')); } - console.log('cookie uuids', uuids); // start auto refresh timer window.setInterval(refreshWindow, 5000); @@ -110,18 +111,30 @@ $(document).ready(function() { // add new entity to list $('#addEntity button').click(function() { - uuids.push($(this).prev().val()); - loadEntities(uuids); + addUUID($(this).prev().val()); + loadEntities(); }); + // bind controls + $('#move input').click(plot); + // options - $('input[name=trendline]').change(function() { - jqOptions.seriesDefaults.trendline.show = $(this).attr('checked'); + $('input[name=trendline]').attr('checked', vz.options.plot.seriesDefaults.trendline.show).change(function() { + vz.options.plot.seriesDefaults.trendline.show = $(this).attr('checked'); + drawPlot(); }); - $('input[name=backendUrl]').val(backendUrl); - $('input[name=tuples]').val(tuples); + $('input[name=backendUrl]').val(vz.options.backendUrl).change(function() { + vz.options.backendUrl = $(this).val(); + }); + + $('input[name=tuples]').val(vz.options.tuples).change(function() { + vz.options.tuples = $(this).val(); + }); + + // initialize plot + vz.plot = $.jqplot('plot', [[]], vz.options.plot); // load all entity information - loadEntities(uuids); + loadEntities(); });