diff options
Diffstat (limited to 'js/dojo-1.7.2/dojox/charting')
110 files changed, 33324 insertions, 0 deletions
diff --git a/js/dojo-1.7.2/dojox/charting/BidiSupport.js b/js/dojo-1.7.2/dojox/charting/BidiSupport.js new file mode 100644 index 0000000..cc0dcec --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/BidiSupport.js @@ -0,0 +1,265 @@ +//>>built +define("dojox/charting/BidiSupport", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/array", "dojo/_base/sniff", + "dojo/dom","dojo/dom-construct", + "dojox/gfx", "dojox/gfx/_gfxBidiSupport", "./Chart", "./axis2d/common", "dojox/string/BidiEngine", "dojox/lang/functional"], + function(lang, html, arr, has, dom, domConstruct, g, gBidi, Chart, da, BidiEngine, df){ + + var bidiEngine = new BidiEngine(); + + lang.extend(Chart, { + // summary: + // Add support for bidi scripts. + // description: + // Bidi stands for support for languages with a bidirectional script. + // There's a special need for displaying BIDI text in rtl direction + // in ltr GUI, sometimes needed auto support. + // dojox.charting does not support control over base text direction provided in Dojo. + + // textDir: String + // Bi-directional support, the main variable which is responsible for the direction of the text. + // The text direction can be different than the GUI direction by using this parameter. + // Allowed values: + // 1. "ltr" + // 2. "rtl" + // 3. "auto" - contextual the direction of a text defined by first strong letter. + // By default is as the page direction. + textDir:"", + + getTextDir: function(/*String*/text){ + // summary: + // Return direction of the text. + // description: + // If textDir is ltr or rtl returns the value. + // If it's auto, calls to another function that responsible + // for checking the value, and defining the direction. + // text: + // Used in case textDir is "auto", this case the direction is according to the first + // strong (directionally - which direction is strong defined) letter. + // tags: + // protected. + var textDir = this.textDir == "auto" ? bidiEngine.checkContextual(text) : this.textDir; + // providing default value + if(!textDir){ + textDir = html.style(this.node,"direction"); + } + return textDir; + }, + + postscript: function(node,args){ + // summary: + // Kicks off chart instantiation. + // description: + // Used for setting the textDir of the chart. + // tags: + // private + + // validate textDir + var textDir = args ? (args["textDir"] ? validateTextDir(args["textDir"]) : "") : ""; + // if textDir wasn't defined or was defined wrong, apply default value + textDir = textDir ? textDir : html.style(this.node,"direction"); + this.textDir = textDir; + + this.surface.textDir = textDir; + + // two data structures, used for storing data for further enablement to change + // textDir dynamically + this.htmlElementsRegistry = []; + this.truncatedLabelsRegistry = []; + }, + + setTextDir: function(/*String*/ newTextDir, obj){ + // summary: + // Setter for the textDir attribute. + // description: + // Allows dynamically set the textDir, goes over all the text-children and + // updates their base text direction. + // tags: + // public + + if(newTextDir == this.textDir){ + return this; + } + if(validateTextDir(newTextDir) != null){ + this.textDir = newTextDir; + + // set automatically all the gfx objects that were created by this surface + // (groups, text objects) + this.surface.setTextDir(newTextDir); + + // truncated labels that were created with gfx creator need to recalculate dir + // for case like: "111111A" (A stands for bidi character) and the truncation + // is "111..." If the textDir is auto, the display should be: "...111" but in gfx + // case we will get "111...". Because this.surface.setTextDir will calculate the dir of truncated + // label, which value is "111..." but th real is "111111A". + // each time we created a gfx truncated label we stored it in the truncatedLabelsRegistry, so update now + // the registry. + if(this.truncatedLabelsRegistry && newTextDir == "auto"){ + arr.forEach(this.truncatedLabelsRegistry, function(elem){ + var tDir = this.getTextDir(elem["label"]); + if(elem["element"].textDir != tDir){ + elem["element"].setShape({textDir: tDir}); + } + }, this); + } + + // re-render axes with html labels. for recalculation of the labels + // positions etc. + // create array of keys for all the axis in chart + var axesKeyArr = df.keys(this.axes); + if(axesKeyArr.length > 0){ + // iterate over the axes, and for each that have html labels render it. + arr.forEach(axesKeyArr, function(key, index, arr){ + // get the axis + var axis = this.axes[key]; + // if the axis has html labels + if(axis.htmlElements[0]){ + axis.dirty = true; + axis.render(this.dim, this.offsets); + } + },this); + + // recreate title + if(this.title){ + var forceHtmlLabels = (g.renderer == "canvas"), + labelType = forceHtmlLabels || !has("ie") && !has("opera") ? "html" : "gfx", + tsize = g.normalizedLength(g.splitFontString(this.titleFont).size); + // remove the title + domConstruct.destroy(this.chartTitle); + this.chartTitle =null; + // create the new title + this.chartTitle = da.createText[labelType]( + this, + this.surface, + this.dim.width/2, + this.titlePos=="top" ? tsize + this.margins.t : this.dim.height - this.margins.b, + "middle", + this.title, + this.titleFont, + this.titleFontColor + ); + } + }else{ + // case of pies, spiders etc. + arr.forEach(this.htmlElementsRegistry, function(elem, index, arr){ + var tDir = newTextDir == "auto" ? this.getTextDir(elem[4]) : newTextDir; + if(elem[0].children[0] && elem[0].children[0].dir != tDir){ + dom.destroy(elem[0].children[0]); + elem[0].children[0] = da.createText["html"] + (this, this.surface, elem[1], elem[2], elem[3], elem[4], elem[5], elem[6]).children[0]; + } + },this); + } + } + }, + + truncateBidi: function(elem, label, labelType){ + // summary: + // Enables bidi support for truncated labels. + // description: + // Can be two types of labels: html or gfx. + // gfx labels: + // Need to be stored in registry to be used when the textDir will be set dynamically. + // Additional work on truncated labels is needed for case as 111111A (A stands for "bidi" character rtl directioned). + // let say in this case the truncation is "111..." If the textDir is auto, the display should be: "...111" but in gfx + // case we will get "111...". Because this.surface.setTextDir will calculate the dir of truncated + // label, which value is "111..." but th real is "111111A". + // each time we created a gfx truncated label we store it in the truncatedLabelsRegistry. + // html labels: + // no need for repository (stored in another place). Here we only need to update the current dir according to textDir. + // tags: + // private + + if(labelType == "gfx"){ + // store truncated gfx labels in the data structure. + this.truncatedLabelsRegistry.push({element: elem, label: label}); + if(this.textDir == "auto"){ + elem.setShape({textDir: this.getTextDir(label)}); + } + } + if(labelType == "html" && this.textDir == "auto"){ + elem.children[0].dir = this.getTextDir(label); + } + } + }); + + var extendMethod = function(obj, method, bundleByPrototype, before, after){ + // Some helper function. Used for extending method of obj. + // obj: Object + // The obj we overriding it's method. + // method: String + // The method that is extended, the original method is called before or after + // functions that passed to extendMethod. + // bundleByPrototype: boolean + // There's two methods to extend, using prototype or not. + // before: function + // If defined this function will be executed before the original method. + // after: function + // If defined this function will be executed after the original method. + if(bundleByPrototype){ + var old = obj.prototype[method]; + obj.prototype[method] = + function(){ + var rBefore; + if (before){ + rBefore = before.apply(this, arguments); + } + var r = old.apply(this, rBefore); + if (after){ + r = after.call(this, r, arguments); + } + return r; + }; + }else{ + var old = lang.clone(obj[method]); + obj[method] = + function(){ + var rBefore; + if (before){ + rBefore = before.apply(this, arguments); + } + var r = old.apply(this, arguments); + if (after){ + after(r, arguments); + } + return r; + }; + } + }; + + var labelPreprocess = function(elem, chart, label, truncatedLabel, font, elemType){ + // aditional preprocessing of the labels, needed for rtl base text direction in LTR + // GUI, or for ltr base text direction for RTL GUI. + + var isChartDirectionRtl = (html.style(chart.node,"direction") == "rtl"); + var isBaseTextDirRtl = (chart.getTextDir(label) == "rtl"); + + if(isBaseTextDirRtl && !isChartDirectionRtl){ + label = "<span dir='rtl'>" + label +"</span>"; + } + if(!isBaseTextDirRtl && isChartDirectionRtl){ + label = "<span dir='ltr'>" + label +"</span>"; + } + + return arguments; + }; + + // connect labelPreprocess to run before labelTooltip. + // patch it only is available + if(dojox.charting.axis2d && dojox.charting.axis2d.Default){ + extendMethod(dojox.charting.axis2d.Default,"labelTooltip",true, labelPreprocess, null); + //extendMethod(dijit,"showTooltip",false, labelPreprocess, null); + } + + function htmlCreateText(r, agumentsArr){ + // function to register HTML elements that created by html.createText, this array + // needed for allowing to change textDir dynamically. + agumentsArr[0].htmlElementsRegistry.push([r, agumentsArr[2], agumentsArr[3], agumentsArr[4], agumentsArr[5], agumentsArr[6], agumentsArr[7]]); + } + + extendMethod(da.createText,"html", false, null, htmlCreateText); + + function validateTextDir(textDir){ + return /^(ltr|rtl|auto)$/.test(textDir) ? textDir : null; + } + +}); diff --git a/js/dojo-1.7.2/dojox/charting/Chart.js b/js/dojo-1.7.2/dojox/charting/Chart.js new file mode 100644 index 0000000..084b156 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/Chart.js @@ -0,0 +1,1130 @@ +//>>built +define("dojox/charting/Chart", ["dojo/_base/lang", "dojo/_base/array","dojo/_base/declare", "dojo/_base/html", + "dojo/dom", "dojo/dom-geometry", "dojo/dom-construct","dojo/_base/Color", "dojo/_base/sniff", + "./Element", "./Theme", "./Series", "./axis2d/common", + "dojox/gfx", "dojox/lang/functional", "dojox/lang/functional/fold", "dojox/lang/functional/reversed"], + function(lang, arr, declare, html, + dom, domGeom, domConstruct, Color, has, + Element, Theme, Series, common, + g, func, funcFold, funcReversed){ + /*===== + dojox.charting.__ChartCtorArgs = function(margins, stroke, fill, delayInMs){ + // summary: + // The keyword arguments that can be passed in a Chart constructor. + // + // margins: Object? + // Optional margins for the chart, in the form of { l, t, r, b}. + // stroke: dojox.gfx.Stroke? + // An optional outline/stroke for the chart. + // fill: dojox.gfx.Fill? + // An optional fill for the chart. + // delayInMs: Number + // Delay in ms for delayedRender(). Default: 200. + this.margins = margins; + this.stroke = stroke; + this.fill = fill; + this.delayInMs = delayInMs; + } + =====*/ + var dc = dojox.charting, + clear = func.lambda("item.clear()"), + purge = func.lambda("item.purgeGroup()"), + destroy = func.lambda("item.destroy()"), + makeClean = func.lambda("item.dirty = false"), + makeDirty = func.lambda("item.dirty = true"), + getName = func.lambda("item.name"); + + declare("dojox.charting.Chart", null, { + // summary: + // The main chart object in dojox.charting. This will create a two dimensional + // chart based on dojox.gfx. + // + // description: + // dojox.charting.Chart is the primary object used for any kind of charts. It + // is simple to create--just pass it a node reference, which is used as the + // container for the chart--and a set of optional keyword arguments and go. + // + // Note that like most of dojox.gfx, most of dojox.charting.Chart's methods are + // designed to return a reference to the chart itself, to allow for functional + // chaining. This makes defining everything on a Chart very easy to do. + // + // example: + // Create an area chart, with smoothing. + // | new dojox.charting.Chart(node)) + // | .addPlot("default", { type: "Areas", tension: "X" }) + // | .setTheme(dojox.charting.themes.Shrooms) + // | .addSeries("Series A", [1, 2, 0.5, 1.5, 1, 2.8, 0.4]) + // | .addSeries("Series B", [2.6, 1.8, 2, 1, 1.4, 0.7, 2]) + // | .addSeries("Series C", [6.3, 1.8, 3, 0.5, 4.4, 2.7, 2]) + // | .render(); + // + // example: + // The form of data in a data series can take a number of forms: a simple array, + // an array of objects {x,y}, or something custom (as determined by the plot). + // Here's an example of a Candlestick chart, which expects an object of + // { open, high, low, close }. + // | new dojox.charting.Chart(node)) + // | .addPlot("default", {type: "Candlesticks", gap: 1}) + // | .addAxis("x", {fixLower: "major", fixUpper: "major", includeZero: true}) + // | .addAxis("y", {vertical: true, fixLower: "major", fixUpper: "major", natural: true}) + // | .addSeries("Series A", [ + // | { open: 20, close: 16, high: 22, low: 8 }, + // | { open: 16, close: 22, high: 26, low: 6, mid: 18 }, + // | { open: 22, close: 18, high: 22, low: 11, mid: 21 }, + // | { open: 18, close: 29, high: 32, low: 14, mid: 27 }, + // | { open: 29, close: 24, high: 29, low: 13, mid: 27 }, + // | { open: 24, close: 8, high: 24, low: 5 }, + // | { open: 8, close: 16, high: 22, low: 2 }, + // | { open: 16, close: 12, high: 19, low: 7 }, + // | { open: 12, close: 20, high: 22, low: 8 }, + // | { open: 20, close: 16, high: 22, low: 8 }, + // | { open: 16, close: 22, high: 26, low: 6, mid: 18 }, + // | { open: 22, close: 18, high: 22, low: 11, mid: 21 }, + // | { open: 18, close: 29, high: 32, low: 14, mid: 27 }, + // | { open: 29, close: 24, high: 29, low: 13, mid: 27 }, + // | { open: 24, close: 8, high: 24, low: 5 }, + // | { open: 8, close: 16, high: 22, low: 2 }, + // | { open: 16, close: 12, high: 19, low: 7 }, + // | { open: 12, close: 20, high: 22, low: 8 }, + // | { open: 20, close: 16, high: 22, low: 8 }, + // | { open: 16, close: 22, high: 26, low: 6 }, + // | { open: 22, close: 18, high: 22, low: 11 }, + // | { open: 18, close: 29, high: 32, low: 14 }, + // | { open: 29, close: 24, high: 29, low: 13 }, + // | { open: 24, close: 8, high: 24, low: 5 }, + // | { open: 8, close: 16, high: 22, low: 2 }, + // | { open: 16, close: 12, high: 19, low: 7 }, + // | { open: 12, close: 20, high: 22, low: 8 }, + // | { open: 20, close: 16, high: 22, low: 8 } + // | ], + // | { stroke: { color: "green" }, fill: "lightgreen" } + // | ) + // | .render(); + + // theme: dojox.charting.Theme? + // An optional theme to use for styling the chart. + // axes: dojox.charting.Axis{}? + // A map of axes for use in plotting a chart. + // stack: dojox.charting.plot2d.Base[] + // A stack of plotters. + // plots: dojox.charting.plot2d.Base{} + // A map of plotter indices + // series: dojox.charting.Series[] + // The stack of data runs used to create plots. + // runs: dojox.charting.Series{} + // A map of series indices + // margins: Object? + // The margins around the chart. Default is { l:10, t:10, r:10, b:10 }. + // stroke: dojox.gfx.Stroke? + // The outline of the chart (stroke in vector graphics terms). + // fill: dojox.gfx.Fill? + // The color for the chart. + // node: DOMNode + // The container node passed to the constructor. + // surface: dojox.gfx.Surface + // The main graphics surface upon which a chart is drawn. + // dirty: Boolean + // A boolean flag indicating whether or not the chart needs to be updated/re-rendered. + // coords: Object + // The coordinates on a page of the containing node, as returned from dojo.coords. + + constructor: function(/* DOMNode */node, /* dojox.charting.__ChartCtorArgs? */kwArgs){ + // summary: + // The constructor for a new Chart. Initializes all parameters used for a chart. + // returns: dojox.charting.Chart + // The newly created chart. + + // initialize parameters + if(!kwArgs){ kwArgs = {}; } + this.margins = kwArgs.margins ? kwArgs.margins : {l: 10, t: 10, r: 10, b: 10}; + this.stroke = kwArgs.stroke; + this.fill = kwArgs.fill; + this.delayInMs = kwArgs.delayInMs || 200; + this.title = kwArgs.title; + this.titleGap = kwArgs.titleGap; + this.titlePos = kwArgs.titlePos; + this.titleFont = kwArgs.titleFont; + this.titleFontColor = kwArgs.titleFontColor; + this.chartTitle = null; + + // default initialization + this.theme = null; + this.axes = {}; // map of axes + this.stack = []; // stack of plotters + this.plots = {}; // map of plotter indices + this.series = []; // stack of data runs + this.runs = {}; // map of data run indices + this.dirty = true; + this.coords = null; + + // create a surface + this.node = dom.byId(node); + var box = domGeom.getMarginBox(node); + this.surface = g.createSurface(this.node, box.w || 400, box.h || 300); + }, + destroy: function(){ + // summary: + // Cleanup when a chart is to be destroyed. + // returns: void + arr.forEach(this.series, destroy); + arr.forEach(this.stack, destroy); + func.forIn(this.axes, destroy); + if(this.chartTitle && this.chartTitle.tagName){ + // destroy title if it is a DOM node + domConstruct.destroy(this.chartTitle); + } + this.surface.destroy(); + }, + getCoords: function(){ + // summary: + // Get the coordinates and dimensions of the containing DOMNode, as + // returned by dojo.coords. + // returns: Object + // The resulting coordinates of the chart. See dojo.coords for details. + return html.coords(this.node, true); // Object + }, + setTheme: function(theme){ + // summary: + // Set a theme of the chart. + // theme: dojox.charting.Theme + // The theme to be used for visual rendering. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + this.theme = theme.clone(); + this.dirty = true; + return this; // dojox.charting.Chart + }, + addAxis: function(name, kwArgs){ + // summary: + // Add an axis to the chart, for rendering. + // name: String + // The name of the axis. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // An optional keyword arguments object for use in defining details of an axis. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var axis, axisType = kwArgs && kwArgs.type || "Default"; + if(typeof axisType == "string"){ + if(!dc.axis2d || !dc.axis2d[axisType]){ + throw Error("Can't find axis: " + axisType + " - Check " + "require() dependencies."); + } + axis = new dc.axis2d[axisType](this, kwArgs); + }else{ + axis = new axisType(this, kwArgs); + } + axis.name = name; + axis.dirty = true; + if(name in this.axes){ + this.axes[name].destroy(); + } + this.axes[name] = axis; + this.dirty = true; + return this; // dojox.charting.Chart + }, + getAxis: function(name){ + // summary: + // Get the given axis, by name. + // name: String + // The name the axis was defined by. + // returns: dojox.charting.axis2d.Default + // The axis as stored in the chart's axis map. + return this.axes[name]; // dojox.charting.axis2d.Default + }, + removeAxis: function(name){ + // summary: + // Remove the axis that was defined using name. + // name: String + // The axis name, as defined in addAxis. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.axes){ + // destroy the axis + this.axes[name].destroy(); + delete this.axes[name]; + // mark the chart as dirty + this.dirty = true; + } + return this; // dojox.charting.Chart + }, + addPlot: function(name, kwArgs){ + // summary: + // Add a new plot to the chart, defined by name and using the optional keyword arguments object. + // Note that dojox.charting assumes the main plot to be called "default"; if you do not have + // a plot called "default" and attempt to add data series to the chart without specifying the + // plot to be rendered on, you WILL get errors. + // name: String + // The name of the plot to be added to the chart. If you only plan on using one plot, call it "default". + // kwArgs: dojox.charting.plot2d.__PlotCtorArgs + // An object with optional parameters for the plot in question. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var plot, plotType = kwArgs && kwArgs.type || "Default"; + if(typeof plotType == "string"){ + if(!dc.plot2d || !dc.plot2d[plotType]){ + throw Error("Can't find plot: " + plotType + " - didn't you forget to dojo" + ".require() it?"); + } + plot = new dc.plot2d[plotType](this, kwArgs); + }else{ + plot = new plotType(this, kwArgs); + } + plot.name = name; + plot.dirty = true; + if(name in this.plots){ + this.stack[this.plots[name]].destroy(); + this.stack[this.plots[name]] = plot; + }else{ + this.plots[name] = this.stack.length; + this.stack.push(plot); + } + this.dirty = true; + return this; // dojox.charting.Chart + }, + getPlot: function(name){ + // summary: + // Get the given plot, by name. + // name: String + // The name the plot was defined by. + // returns: dojox.charting.plot2d.Base + // The plot. + return this.stack[this.plots[name]]; + }, + removePlot: function(name){ + // summary: + // Remove the plot defined using name from the chart's plot stack. + // name: String + // The name of the plot as defined using addPlot. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.plots){ + // get the index and remove the name + var index = this.plots[name]; + delete this.plots[name]; + // destroy the plot + this.stack[index].destroy(); + // remove the plot from the stack + this.stack.splice(index, 1); + // update indices to reflect the shift + func.forIn(this.plots, function(idx, name, plots){ + if(idx > index){ + plots[name] = idx - 1; + } + }); + // remove all related series + var ns = arr.filter(this.series, function(run){ return run.plot != name; }); + if(ns.length < this.series.length){ + // kill all removed series + arr.forEach(this.series, function(run){ + if(run.plot == name){ + run.destroy(); + } + }); + // rebuild all necessary data structures + this.runs = {}; + arr.forEach(ns, function(run, index){ + this.runs[run.plot] = index; + }, this); + this.series = ns; + } + // mark the chart as dirty + this.dirty = true; + } + return this; // dojox.charting.Chart + }, + getPlotOrder: function(){ + // summary: + // Returns an array of plot names in the current order + // (the top-most plot is the first). + // returns: Array + return func.map(this.stack, getName); // Array + }, + setPlotOrder: function(newOrder){ + // summary: + // Sets new order of plots. newOrder cannot add or remove + // plots. Wrong names, or dups are ignored. + // newOrder: Array: + // Array of plot names compatible with getPlotOrder(). + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var names = {}, + order = func.filter(newOrder, function(name){ + if(!(name in this.plots) || (name in names)){ + return false; + } + names[name] = 1; + return true; + }, this); + if(order.length < this.stack.length){ + func.forEach(this.stack, function(plot){ + var name = plot.name; + if(!(name in names)){ + order.push(name); + } + }); + } + var newStack = func.map(order, function(name){ + return this.stack[this.plots[name]]; + }, this); + func.forEach(newStack, function(plot, i){ + this.plots[plot.name] = i; + }, this); + this.stack = newStack; + this.dirty = true; + return this; // dojox.charting.Chart + }, + movePlotToFront: function(name){ + // summary: + // Moves a given plot to front. + // name: String: + // Plot's name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.plots){ + var index = this.plots[name]; + if(index){ + var newOrder = this.getPlotOrder(); + newOrder.splice(index, 1); + newOrder.unshift(name); + return this.setPlotOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + movePlotToBack: function(name){ + // summary: + // Moves a given plot to back. + // name: String: + // Plot's name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.plots){ + var index = this.plots[name]; + if(index < this.stack.length - 1){ + var newOrder = this.getPlotOrder(); + newOrder.splice(index, 1); + newOrder.push(name); + return this.setPlotOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + addSeries: function(name, data, kwArgs){ + // summary: + // Add a data series to the chart for rendering. + // name: String: + // The name of the data series to be plotted. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + // kwArgs: dojox.charting.__SeriesCtorArgs?: + // An optional keyword arguments object that will be mixed into + // the resultant series object. + // returns: dojox.charting.Chart: + // A reference to the current chart for functional chaining. + var run = new Series(this, data, kwArgs); + run.name = name; + if(name in this.runs){ + this.series[this.runs[name]].destroy(); + this.series[this.runs[name]] = run; + }else{ + this.runs[name] = this.series.length; + this.series.push(run); + } + this.dirty = true; + // fix min/max + if(!("ymin" in run) && "min" in run){ run.ymin = run.min; } + if(!("ymax" in run) && "max" in run){ run.ymax = run.max; } + return this; // dojox.charting.Chart + }, + getSeries: function(name){ + // summary: + // Get the given series, by name. + // name: String + // The name the series was defined by. + // returns: dojox.charting.Series + // The series. + return this.series[this.runs[name]]; + }, + removeSeries: function(name){ + // summary: + // Remove the series defined by name from the chart. + // name: String + // The name of the series as defined by addSeries. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + // get the index and remove the name + var index = this.runs[name]; + delete this.runs[name]; + // destroy the run + this.series[index].destroy(); + // remove the run from the stack of series + this.series.splice(index, 1); + // update indices to reflect the shift + func.forIn(this.runs, function(idx, name, runs){ + if(idx > index){ + runs[name] = idx - 1; + } + }); + this.dirty = true; + } + return this; // dojox.charting.Chart + }, + updateSeries: function(name, data){ + // summary: + // Update the given series with a new set of data points. + // name: String + // The name of the series as defined in addSeries. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + var run = this.series[this.runs[name]]; + run.update(data); + this._invalidateDependentPlots(run.plot, false); + this._invalidateDependentPlots(run.plot, true); + } + return this; // dojox.charting.Chart + }, + getSeriesOrder: function(plotName){ + // summary: + // Returns an array of series names in the current order + // (the top-most series is the first) within a plot. + // plotName: String: + // Plot's name. + // returns: Array + return func.map(func.filter(this.series, function(run){ + return run.plot == plotName; + }), getName); + }, + setSeriesOrder: function(newOrder){ + // summary: + // Sets new order of series within a plot. newOrder cannot add + // or remove series. Wrong names, or dups are ignored. + // newOrder: Array: + // Array of series names compatible with getPlotOrder(). All + // series should belong to the same plot. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var plotName, names = {}, + order = func.filter(newOrder, function(name){ + if(!(name in this.runs) || (name in names)){ + return false; + } + var run = this.series[this.runs[name]]; + if(plotName){ + if(run.plot != plotName){ + return false; + } + }else{ + plotName = run.plot; + } + names[name] = 1; + return true; + }, this); + func.forEach(this.series, function(run){ + var name = run.name; + if(!(name in names) && run.plot == plotName){ + order.push(name); + } + }); + var newSeries = func.map(order, function(name){ + return this.series[this.runs[name]]; + }, this); + this.series = newSeries.concat(func.filter(this.series, function(run){ + return run.plot != plotName; + })); + func.forEach(this.series, function(run, i){ + this.runs[run.name] = i; + }, this); + this.dirty = true; + return this; // dojox.charting.Chart + }, + moveSeriesToFront: function(name){ + // summary: + // Moves a given series to front of a plot. + // name: String: + // Series' name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + var index = this.runs[name], + newOrder = this.getSeriesOrder(this.series[index].plot); + if(name != newOrder[0]){ + newOrder.splice(index, 1); + newOrder.unshift(name); + return this.setSeriesOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + moveSeriesToBack: function(name){ + // summary: + // Moves a given series to back of a plot. + // name: String: + // Series' name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + var index = this.runs[name], + newOrder = this.getSeriesOrder(this.series[index].plot); + if(name != newOrder[newOrder.length - 1]){ + newOrder.splice(index, 1); + newOrder.push(name); + return this.setSeriesOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + resize: function(width, height){ + // summary: + // Resize the chart to the dimensions of width and height. + // description: + // Resize the chart and its surface to the width and height dimensions. + // If no width/height or box is provided, resize the surface to the marginBox of the chart. + // width: Number + // The new width of the chart. + // height: Number + // The new height of the chart. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var box; + switch(arguments.length){ + // case 0, do not resize the div, just the surface + case 1: + // argument, override node box + box = lang.mixin({}, width); + domGeom.setMarginBox(this.node, box); + break; + case 2: + box = {w: width, h: height}; + // argument, override node box + domGeom.setMarginBox(this.node, box); + break; + } + // in all cases take back the computed box + box = domGeom.getMarginBox(this.node); + var d = this.surface.getDimensions(); + if(d.width != box.w || d.height != box.h){ + // and set it on the surface + this.surface.setDimensions(box.w, box.h); + this.dirty = true; + return this.render(); // dojox.charting.Chart + }else{ + return this; + } + }, + getGeometry: function(){ + // summary: + // Returns a map of information about all axes in a chart and what they represent + // in terms of scaling (see dojox.charting.axis2d.Default.getScaler). + // returns: Object + // An map of geometry objects, a one-to-one mapping of axes. + var ret = {}; + func.forIn(this.axes, function(axis){ + if(axis.initialized()){ + ret[axis.name] = { + name: axis.name, + vertical: axis.vertical, + scaler: axis.scaler, + ticks: axis.ticks + }; + } + }); + return ret; // Object + }, + setAxisWindow: function(name, scale, offset, zoom){ + // summary: + // Zooms an axis and all dependent plots. Can be used to zoom in 1D. + // name: String + // The name of the axis as defined by addAxis. + // scale: Number + // The scale on the target axis. + // offset: Number + // Any offest, as measured by axis tick + // zoom: Boolean|Object? + // The chart zooming animation trigger. This is null by default, + // e.g. {duration: 1200}, or just set true. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var axis = this.axes[name]; + if(axis){ + axis.setWindow(scale, offset); + arr.forEach(this.stack,function(plot){ + if(plot.hAxis == name || plot.vAxis == name){ + plot.zoom = zoom; + } + }); + } + return this; // dojox.charting.Chart + }, + setWindow: function(sx, sy, dx, dy, zoom){ + // summary: + // Zooms in or out any plots in two dimensions. + // sx: Number + // The scale for the x axis. + // sy: Number + // The scale for the y axis. + // dx: Number + // The pixel offset on the x axis. + // dy: Number + // The pixel offset on the y axis. + // zoom: Boolean|Object? + // The chart zooming animation trigger. This is null by default, + // e.g. {duration: 1200}, or just set true. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(!("plotArea" in this)){ + this.calculateGeometry(); + } + func.forIn(this.axes, function(axis){ + var scale, offset, bounds = axis.getScaler().bounds, + s = bounds.span / (bounds.upper - bounds.lower); + if(axis.vertical){ + scale = sy; + offset = dy / s / scale; + }else{ + scale = sx; + offset = dx / s / scale; + } + axis.setWindow(scale, offset); + }); + arr.forEach(this.stack, function(plot){ plot.zoom = zoom; }); + return this; // dojox.charting.Chart + }, + zoomIn: function(name, range){ + // summary: + // Zoom the chart to a specific range on one axis. This calls render() + // directly as a convenience method. + // name: String + // The name of the axis as defined by addAxis. + // range: Array + // The end points of the zoom range, measured in axis ticks. + var axis = this.axes[name]; + if(axis){ + var scale, offset, bounds = axis.getScaler().bounds; + var lower = Math.min(range[0],range[1]); + var upper = Math.max(range[0],range[1]); + lower = range[0] < bounds.lower ? bounds.lower : lower; + upper = range[1] > bounds.upper ? bounds.upper : upper; + scale = (bounds.upper - bounds.lower) / (upper - lower); + offset = lower - bounds.lower; + this.setAxisWindow(name, scale, offset); + this.render(); + } + }, + calculateGeometry: function(){ + // summary: + // Calculate the geometry of the chart based on the defined axes of + // a chart. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(this.dirty){ + return this.fullGeometry(); + } + + // calculate geometry + var dirty = arr.filter(this.stack, function(plot){ + return plot.dirty || + (plot.hAxis && this.axes[plot.hAxis].dirty) || + (plot.vAxis && this.axes[plot.vAxis].dirty); + }, this); + calculateAxes(dirty, this.plotArea); + + return this; // dojox.charting.Chart + }, + fullGeometry: function(){ + // summary: + // Calculate the full geometry of the chart. This includes passing + // over all major elements of a chart (plots, axes, series, container) + // in order to ensure proper rendering. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + this._makeDirty(); + + // clear old values + arr.forEach(this.stack, clear); + + // rebuild new connections, and add defaults + + // set up a theme + if(!this.theme){ + this.setTheme(new Theme(dojox.charting._def)); + } + + // assign series + arr.forEach(this.series, function(run){ + if(!(run.plot in this.plots)){ + if(!dc.plot2d || !dc.plot2d.Default){ + throw Error("Can't find plot: Default - didn't you forget to dojo" + ".require() it?"); + } + var plot = new dc.plot2d.Default(this, {}); + plot.name = run.plot; + this.plots[run.plot] = this.stack.length; + this.stack.push(plot); + } + this.stack[this.plots[run.plot]].addSeries(run); + }, this); + // assign axes + arr.forEach(this.stack, function(plot){ + if(plot.hAxis){ + plot.setAxis(this.axes[plot.hAxis]); + } + if(plot.vAxis){ + plot.setAxis(this.axes[plot.vAxis]); + } + }, this); + + // calculate geometry + + // 1st pass + var dim = this.dim = this.surface.getDimensions(); + dim.width = g.normalizedLength(dim.width); + dim.height = g.normalizedLength(dim.height); + func.forIn(this.axes, clear); + calculateAxes(this.stack, dim); + + // assumption: we don't have stacked axes yet + var offsets = this.offsets = { l: 0, r: 0, t: 0, b: 0 }; + func.forIn(this.axes, function(axis){ + func.forIn(axis.getOffsets(), function(o, i){ offsets[i] += o; }); + }); + // add title area + if(this.title){ + this.titleGap = (this.titleGap==0) ? 0 : this.titleGap || this.theme.chart.titleGap || 20; + this.titlePos = this.titlePos || this.theme.chart.titlePos || "top"; + this.titleFont = this.titleFont || this.theme.chart.titleFont; + this.titleFontColor = this.titleFontColor || this.theme.chart.titleFontColor || "black"; + var tsize = g.normalizedLength(g.splitFontString(this.titleFont).size); + offsets[this.titlePos=="top" ? "t":"b"] += (tsize + this.titleGap); + } + // add margins + func.forIn(this.margins, function(o, i){ offsets[i] += o; }); + + // 2nd pass with realistic dimensions + this.plotArea = { + width: dim.width - offsets.l - offsets.r, + height: dim.height - offsets.t - offsets.b + }; + func.forIn(this.axes, clear); + calculateAxes(this.stack, this.plotArea); + + return this; // dojox.charting.Chart + }, + render: function(){ + // summary: + // Render the chart according to the current information defined. This should + // be the last call made when defining/creating a chart, or if data within the + // chart has been changed. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(this.theme){ + this.theme.clear(); + } + + if(this.dirty){ + return this.fullRender(); + } + + this.calculateGeometry(); + + // go over the stack backwards + func.forEachRev(this.stack, function(plot){ plot.render(this.dim, this.offsets); }, this); + + // go over axes + func.forIn(this.axes, function(axis){ axis.render(this.dim, this.offsets); }, this); + + this._makeClean(); + + // BEGIN FOR HTML CANVAS + if(this.surface.render){ this.surface.render(); }; + // END FOR HTML CANVAS + + return this; // dojox.charting.Chart + }, + fullRender: function(){ + // summary: + // Force a full rendering of the chart, including full resets on the chart itself. + // You should not call this method directly unless absolutely necessary. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + + // calculate geometry + this.fullGeometry(); + var offsets = this.offsets, dim = this.dim, rect; + + // get required colors + //var requiredColors = func.foldl(this.stack, "z + plot.getRequiredColors()", 0); + //this.theme.defineColors({num: requiredColors, cache: false}); + + // clear old shapes + arr.forEach(this.series, purge); + func.forIn(this.axes, purge); + arr.forEach(this.stack, purge); + if(this.chartTitle && this.chartTitle.tagName){ + // destroy title if it is a DOM node + domConstruct.destroy(this.chartTitle); + } + this.surface.clear(); + this.chartTitle = null; + + // generate shapes + + // draw a plot background + var t = this.theme, + fill = t.plotarea && t.plotarea.fill, + stroke = t.plotarea && t.plotarea.stroke, + // size might be neg if offsets are bigger that chart size this happens quite often at + // initialization time if the chart widget is used in a BorderContainer + // this will fail on IE/VML + w = Math.max(0, dim.width - offsets.l - offsets.r), + h = Math.max(0, dim.height - offsets.t - offsets.b), + rect = { + x: offsets.l - 1, y: offsets.t - 1, + width: w + 2, + height: h + 2 + }; + if(fill){ + fill = Element.prototype._shapeFill(Element.prototype._plotFill(fill, dim, offsets), rect); + this.surface.createRect(rect).setFill(fill); + } + if(stroke){ + this.surface.createRect({ + x: offsets.l, y: offsets.t, + width: w + 1, + height: h + 1 + }).setStroke(stroke); + } + + // go over the stack backwards + func.foldr(this.stack, function(z, plot){ return plot.render(dim, offsets), 0; }, 0); + + // pseudo-clipping: matting + fill = this.fill !== undefined ? this.fill : (t.chart && t.chart.fill); + stroke = this.stroke !== undefined ? this.stroke : (t.chart && t.chart.stroke); + + // TRT: support for "inherit" as a named value in a theme. + if(fill == "inherit"){ + // find the background color of the nearest ancestor node, and use that explicitly. + var node = this.node, fill = new Color(html.style(node, "backgroundColor")); + while(fill.a==0 && node!=document.documentElement){ + fill = new Color(html.style(node, "backgroundColor")); + node = node.parentNode; + } + } + + if(fill){ + fill = Element.prototype._plotFill(fill, dim, offsets); + if(offsets.l){ // left + rect = { + width: offsets.l, + height: dim.height + 1 + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + if(offsets.r){ // right + rect = { + x: dim.width - offsets.r, + width: offsets.r + 1, + height: dim.height + 2 + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + if(offsets.t){ // top + rect = { + width: dim.width + 1, + height: offsets.t + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + if(offsets.b){ // bottom + rect = { + y: dim.height - offsets.b, + width: dim.width + 1, + height: offsets.b + 2 + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + } + if(stroke){ + this.surface.createRect({ + width: dim.width - 1, + height: dim.height - 1 + }).setStroke(stroke); + } + + //create title: Whether to make chart title as a widget which extends dojox.charting.Element? + if(this.title){ + var forceHtmlLabels = (g.renderer == "canvas"), + labelType = forceHtmlLabels || !has("ie") && !has("opera") ? "html" : "gfx", + tsize = g.normalizedLength(g.splitFontString(this.titleFont).size); + this.chartTitle = common.createText[labelType]( + this, + this.surface, + dim.width/2, + this.titlePos=="top" ? tsize + this.margins.t : dim.height - this.margins.b, + "middle", + this.title, + this.titleFont, + this.titleFontColor + ); + } + + // go over axes + func.forIn(this.axes, function(axis){ axis.render(dim, offsets); }); + + this._makeClean(); + + // BEGIN FOR HTML CANVAS + if(this.surface.render){ this.surface.render(); }; + // END FOR HTML CANVAS + + return this; // dojox.charting.Chart + }, + delayedRender: function(){ + // summary: + // Delayed render, which is used to collect multiple updates + // within a delayInMs time window. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + + if(!this._delayedRenderHandle){ + this._delayedRenderHandle = setTimeout( + lang.hitch(this, function(){ + clearTimeout(this._delayedRenderHandle); + this._delayedRenderHandle = null; + this.render(); + }), + this.delayInMs + ); + } + + return this; // dojox.charting.Chart + }, + connectToPlot: function(name, object, method){ + // summary: + // A convenience method to connect a function to a plot. + // name: String + // The name of the plot as defined by addPlot. + // object: Object + // The object to be connected. + // method: Function + // The function to be executed. + // returns: Array + // A handle to the connection, as defined by dojo.connect (see dojo.connect). + return name in this.plots ? this.stack[this.plots[name]].connect(object, method) : null; // Array + }, + fireEvent: function(seriesName, eventName, index){ + // summary: + // Fires a synthetic event for a series item. + // seriesName: String: + // Series name. + // eventName: String: + // Event name to simulate: onmouseover, onmouseout, onclick. + // index: Number: + // Valid data value index for the event. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(seriesName in this.runs){ + var plotName = this.series[this.runs[seriesName]].plot; + if(plotName in this.plots){ + var plot = this.stack[this.plots[plotName]]; + if(plot){ + plot.fireEvent(seriesName, eventName, index); + } + } + } + return this; // dojox.charting.Chart + }, + _makeClean: function(){ + // reset dirty flags + arr.forEach(this.axes, makeClean); + arr.forEach(this.stack, makeClean); + arr.forEach(this.series, makeClean); + this.dirty = false; + }, + _makeDirty: function(){ + // reset dirty flags + arr.forEach(this.axes, makeDirty); + arr.forEach(this.stack, makeDirty); + arr.forEach(this.series, makeDirty); + this.dirty = true; + }, + _invalidateDependentPlots: function(plotName, /* Boolean */ verticalAxis){ + if(plotName in this.plots){ + var plot = this.stack[this.plots[plotName]], axis, + axisName = verticalAxis ? "vAxis" : "hAxis"; + if(plot[axisName]){ + axis = this.axes[plot[axisName]]; + if(axis && axis.dependOnData()){ + axis.dirty = true; + // find all plots and mark them dirty + arr.forEach(this.stack, function(p){ + if(p[axisName] && p[axisName] == plot[axisName]){ + p.dirty = true; + } + }); + } + }else{ + plot.dirty = true; + } + } + } + }); + + function hSection(stats){ + return {min: stats.hmin, max: stats.hmax}; + } + + function vSection(stats){ + return {min: stats.vmin, max: stats.vmax}; + } + + function hReplace(stats, h){ + stats.hmin = h.min; + stats.hmax = h.max; + } + + function vReplace(stats, v){ + stats.vmin = v.min; + stats.vmax = v.max; + } + + function combineStats(target, source){ + if(target && source){ + target.min = Math.min(target.min, source.min); + target.max = Math.max(target.max, source.max); + } + return target || source; + } + + function calculateAxes(stack, plotArea){ + var plots = {}, axes = {}; + arr.forEach(stack, function(plot){ + var stats = plots[plot.name] = plot.getSeriesStats(); + if(plot.hAxis){ + axes[plot.hAxis] = combineStats(axes[plot.hAxis], hSection(stats)); + } + if(plot.vAxis){ + axes[plot.vAxis] = combineStats(axes[plot.vAxis], vSection(stats)); + } + }); + arr.forEach(stack, function(plot){ + var stats = plots[plot.name]; + if(plot.hAxis){ + hReplace(stats, axes[plot.hAxis]); + } + if(plot.vAxis){ + vReplace(stats, axes[plot.vAxis]); + } + plot.initializeScalers(plotArea, stats); + }); + } + + return dojox.charting.Chart; +}); diff --git a/js/dojo-1.7.2/dojox/charting/Chart2D.js b/js/dojo-1.7.2/dojox/charting/Chart2D.js new file mode 100644 index 0000000..4ab898f --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/Chart2D.js @@ -0,0 +1,17 @@ +//>>built +define("dojox/charting/Chart2D", ["dojo/_base/kernel", "dojox", "./Chart", + "./axis2d/Default", "./axis2d/Invisible", "./plot2d/Default", "./plot2d/Lines", "./plot2d/Areas", + "./plot2d/Markers", "./plot2d/MarkersOnly", "./plot2d/Scatter", "./plot2d/Stacked", "./plot2d/StackedLines", + "./plot2d/StackedAreas", "./plot2d/Columns", "./plot2d/StackedColumns", "./plot2d/ClusteredColumns", + "./plot2d/Bars", "./plot2d/StackedBars", "./plot2d/ClusteredBars", "./plot2d/Grid", "./plot2d/Pie", + "./plot2d/Bubble", "./plot2d/Candlesticks", "./plot2d/OHLC", "./plot2d/Spider"], + function(dojo, dojox, Chart){ + dojo.deprecated("dojox.charting.Chart2D", "Use dojo.charting.Chart instead and require all other components explicitly", "2.0"); + // module: + // dojox/charting/Chart2D + // summary: + // This is a compatibility module which loads all charting modules that used to be automatically + // loaded in versions prior to 1.6. It is highly recommended for performance reasons that + // this module no longer be referenced by applications. Instead, use dojox/charting/Chart. + return dojox.charting.Chart2D = Chart; +}); diff --git a/js/dojo-1.7.2/dojox/charting/Chart3D.js b/js/dojo-1.7.2/dojox/charting/Chart3D.js new file mode 100644 index 0000000..6d25dc1 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/Chart3D.js @@ -0,0 +1,100 @@ +//>>built +define("dojox/charting/Chart3D", ["dojo/_base/array", "dojo/dom","dojo/_base/declare", "dojo/_base/html", "dojox/gfx", "dojox/gfx3d"], + function(arr, dom, declare, html, gfx, gfx3d){ + // module: + // dojox/charting/Chart3D + // summary: + // This module provides basic 3d charting capablities (using 2d vector graphics to simulate 3d. + + /*===== + dojox.charting.__Chart3DCtorArgs = function(node, lights, camera, theme){ + // summary: + // The keyword arguments that can be passed in a Chart constructor. + // + // node: Node + // The DOM node to construct the chart on. + // lights: + // Lighting properties for the 3d scene + // camera: Object + // Camera properties describing the viewing camera position. + // theme: Object + // Charting theme to use for coloring chart elements. + } + =====*/ + var observerVector = {x: 0, y: 0, z: 1}, v = gfx3d.vector, n = gfx.normalizedLength; + + return declare("dojox.charting.Chart3D", null, { + constructor: function(node, lights, camera, theme){ + // setup a view + this.node = dom.byId(node); + this.surface = gfx.createSurface(this.node, n(this.node.style.width), n(this.node.style.height)); + this.view = this.surface.createViewport(); + this.view.setLights(lights.lights, lights.ambient, lights.specular); + this.view.setCameraTransform(camera); + this.theme = theme; + + // initialize internal variables + this.walls = []; + this.plots = []; + }, + + // public API + generate: function(){ + return this._generateWalls()._generatePlots(); + }, + invalidate: function(){ + this.view.invalidate(); + return this; + }, + render: function(){ + this.view.render(); + return this; + }, + addPlot: function(plot){ + return this._add(this.plots, plot); + }, + removePlot: function(plot){ + return this._remove(this.plots, plot); + }, + addWall: function(wall){ + return this._add(this.walls, wall); + }, + removeWall: function(wall){ + return this._remove(this.walls, wall); + }, + + // internal API + _add: function(array, item){ + if(!arr.some(array, function(i){ return i == item; })){ + array.push(item); + this.view.invalidate(); + } + return this; + }, + _remove: function(array, item){ + var a = arr.filter(array, function(i){ return i != item; }); + return a.length < array.length ? (array = a, this.invalidate()) : this; + }, + _generateWalls: function(){ + for(var i = 0; i < this.walls.length; ++i){ + if(v.dotProduct(observerVector, this.walls[i].normal) > 0){ + this.walls[i].generate(this); + } + } + return this; + }, + _generatePlots: function(){ + var depth = 0, m = gfx3d.matrix, i = 0; + for(; i < this.plots.length; ++i){ + depth += this.plots[i].getDepth(); + } + for(--i; i >= 0; --i){ + var scene = this.view.createScene(); + scene.setTransform(m.translate(0, 0, -depth)); + this.plots[i].generate(this, scene); + depth -= this.plots[i].getDepth(); + } + return this; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/DataChart.js b/js/dojo-1.7.2/dojox/charting/DataChart.js new file mode 100644 index 0000000..d960612 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/DataChart.js @@ -0,0 +1,519 @@ +//>>built +define("dojox/charting/DataChart", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/html", "dojo/_base/connect", + "dojo/_base/array", "./Chart2D", "./themes/PlotKit/blue", "dojo/dom"], + function(kernel, lang, declare, html, hub, arr, Chart, blue, dom){ + // FIXME: This module drags in all Charting modules because of the Chart2D dependency...it is VERY heavy + kernel.experimental("dojox.charting.DataChart"); + + // Defaults for axes + // to be mixed in with xaxis/yaxis custom properties + // see dojox.charting.axis2d.Default for details. + var _yaxis = { + vertical: true, + min: 0, + max: 10, + majorTickStep: 5, + minorTickStep: 1, + natural:false, + stroke: "black", + majorTick: {stroke: "black", length: 8}, + minorTick: {stroke: "gray", length: 2}, + majorLabels:true + }; + + var _xaxis = { + natural: true, // true - no fractions + majorLabels: true, //show labels on major ticks + includeZero: false, // do not change on upating chart + majorTickStep: 1, + majorTick: {stroke: "black", length: 8}, + fixUpper:"major", + stroke: "black", + htmlLabels: true, + from:1 + }; + + // default for chart elements + var chartPlot = { + markers: true, + tension:2, + gap:2 + }; + /*===== + var Chart = dojox.charting.Chart; + =====*/ + return declare("dojox.charting.DataChart", Chart, { + // summary: + // DataChart + // Extension to the 2D chart that connects to a data store in + // a simple manner. Convenience methods have been added for + // connecting store item labels to the chart labels. + // + // description: + // This code should be considered very experimental and the APIs subject + // to change. This is currently an alpha version and will need some testing + // and review. + // + // The main reason for this extension is to create animated charts, generally + // available with scroll=true, and a property field that gets continually updated. + // The previous property settings are kept in memory and displayed until scrolled + // off the chart. + // + // Although great effort was made to maintain the integrity of the current + // charting APIs, some things have been added or modified in order to get + // the store to connect and also to get the data to scroll/animate. + // "displayRange" in particular is used to force the xaxis to a specific + // size and keep the chart from stretching or squashing to fit the data. + // + // Currently, plot lines can only be set at initialization. Setting + // a new store query will have no effect (although using setStore + // may work but its untested). + // + // example: + // + // | var chart = new dojox.charting.DataChart("myNode", { + // | displayRange:8, + // | store:dataStore, + // | query:{symbol:"*"}, + // | fieldName:"price" + // | type: dojox.charting.plot2d.Columns + // | }); + // + // properties: + // + // scroll: Boolean + // Whether live data updates and changes display, like columns moving + // up and down, or whether it scrolls to the left as data is added + scroll:true, + // + // comparative: Boolean + // If false, all items are each their own series. + // If true, the items are combined into one series + // so that their charted properties can be compared. + comparative:false, + // + // query: String + // Used for fetching items. Will vary depending upon store. + query: "*", + // + // queryOptions: String + // Option used for fetching items + queryOptions: "", + // + /*===== + // start:Number + // first item to fetch from store + // count:Number + // Total amount of items to fetch from store + // sort:Object + // Paramaters to sort the fetched items from store + =====*/ + // + // fieldName: String + // The field in the store item that is getting charted + fieldName: "value", + // + // chartTheme: dojox.charting.themes.* + // The theme to style the chart. Defaults to PlotKit.blue. + chartTheme: blue, + // + // displayRange: Number + // The number of major ticks to show on the xaxis + displayRange:0, + // + // stretchToFit: Boolean + // If true, chart is sized to data. If false, chart is a + // fixed size. Note, is overridden by displayRange. + // TODO: Stretch for the y-axis? + stretchToFit:true, + // + // minWidth: Number + // The the smallest the chart width can be + minWidth:200, + // + // minHeight: Number + // The the smallest the chart height can be + minHeight:100, + // + // showing: Boolean + // Whether the chart is showing (default) on + // initialization or hidden. + showing: true, + // + // label: String + // The name field of the store item + // DO NOT SET: Set from store.labelAttribute + label: "name", + + constructor: function(node, kwArgs){ + // summary: + // Set up properties and initialize chart build. + // + // arguments: + // node: DomNode + // The node to attach the chart to. + // kwArgs: Object + // xaxis: Object + // optional parameters for xaxis (see above) + // yaxis: Object + // optional parameters for yaxis (see above) + // store: Object + // dojo.data store (currently nly supports Persevere) + // xaxis: Object + // First query for store + // grid: Object + // Options for the grid plot + // chartPlot: Object + // Options for chart elements (lines, bars, etc) + + this.domNode = dom.byId(node); + + lang.mixin(this, kwArgs); + + this.xaxis = lang.mixin(lang.mixin({}, _xaxis), kwArgs.xaxis); + if(this.xaxis.labelFunc == "seriesLabels"){ + this.xaxis.labelFunc = lang.hitch(this, "seriesLabels"); + } + + this.yaxis = lang.mixin(lang.mixin({}, _yaxis), kwArgs.yaxis); + if(this.yaxis.labelFunc == "seriesLabels"){ + this.yaxis.labelFunc = lang.hitch(this, "seriesLabels"); + } + + // potential event's collector + this._events = []; + + this.convertLabels(this.yaxis); + this.convertLabels(this.xaxis); + + this.onSetItems = {}; + this.onSetInterval = 0; + this.dataLength = 0; + this.seriesData = {}; + this.seriesDataBk = {}; + this.firstRun = true; + + this.dataOffset = 0; + + // FIXME: looks better with this, but it's custom + this.chartTheme.plotarea.stroke = {color: "gray", width: 3}; + + this.setTheme(this.chartTheme); + + // displayRange overrides stretchToFit + if(this.displayRange){ + this.stretchToFit = false; + } + if(!this.stretchToFit){ + this.xaxis.to = this.displayRange; + } + this.addAxis("x", this.xaxis); + this.addAxis("y", this.yaxis); + chartPlot.type = kwArgs.type || "Markers" + this.addPlot("default", lang.mixin(chartPlot, kwArgs.chartPlot)); + + this.addPlot("grid", lang.mixin(kwArgs.grid || {}, {type: "Grid", hMinorLines: true})); + + if(this.showing){ + this.render(); + } + + if(kwArgs.store){ + this.setStore(kwArgs.store, kwArgs.query, kwArgs.fieldName, kwArgs.queryOptions); + } + }, + + destroy: function(){ + arr.forEach(this._events, hub.disconnect); + this.inherited(arguments); + }, + + setStore: function(/*Object*/store, /* ? String*/query, /* ? String*/fieldName, /* ? Object */queryOptions){ + // summary: + // Sets the chart store and query + // then does the first fetch and + // connects to subsequent changes. + // + // TODO: Not handling resetting store + // + this.firstRun = true; + this.store = store || this.store; + this.query = query || this.query; + this.fieldName = fieldName || this.fieldName; + this.label = this.store.getLabelAttributes(); + this.queryOptions = queryOptions || queryOptions; + + arr.forEach(this._events, hub.disconnect); + this._events = [ + hub.connect(this.store, "onSet", this, "onSet"), + hub.connect(this.store, "onError", this, "onError") + ]; + this.fetch(); + }, + + show: function(){ + // summary: + // If chart is hidden, show it + if(!this.showing){ + html.style(this.domNode, "display", ""); + this.showing = true; + this.render(); + } + }, + hide: function(){ + // summary: + // If chart is showing, hide it + // Prevents rendering while hidden + if(this.showing){ + html.style(this.domNode, "display", "none"); + this.showing = false; + } + }, + + onSet: function(/*storeObject*/item){ + // summary: + // Fired when a store item changes. + // Collects the item calls and when + // done (after 200ms), sends item + // array to onData(). + // + // FIXME: Using labels instead of IDs for item + // identifiers here and in the chart series. This + // is obviously short sighted, but currently used + // for seriesLabels. Workaround for potential bugs + // is to assign a label for which all items are unique. + + var nm = this.getProperty(item, this.label); + + // FIXME: why the check for if-in-runs? + if(nm in this.runs || this.comparative){ + clearTimeout(this.onSetInterval); + if(!this.onSetItems[nm]){ + this.onSetItems[nm] = item; + } + this.onSetInterval = setTimeout(lang.hitch(this, function(){ + clearTimeout(this.onSetInterval); + var items = []; + for(var nm in this.onSetItems){ + items.push(this.onSetItems[nm]); + } + this.onData(items); + this.onSetItems = {}; + }),200); + } + }, + + onError: function(/*Error*/err){ + // stub + // Fires on fetch error + console.error("DataChart Error:", err); + }, + + onDataReceived: function(/*Array*/items){ + // summary: + // stub. Fires after data is received but + // before data is parsed and rendered + }, + + getProperty: function(/*storeObject*/item, prop){ + // summary: + // The main use of this function is to determine + // between a single value and an array of values. + // Other property types included for convenience. + // + if(prop==this.label){ + return this.store.getLabel(item); + } + if(prop=="id"){ + return this.store.getIdentity(item); + } + var value = this.store.getValues(item, prop); + if(value.length < 2){ + value = this.store.getValue(item, prop); + } + return value; + }, + onData: function(/*Array*/items){ + // summary: + // Called after a completed fetch + // or when store items change. + // On first run, sets the chart data, + // then updates chart and legends. + // + //console.log("Store:", store);console.log("items: (", items.length+")", items);console.log("Chart:", this); + if(!items || !items.length){ return; } + + if(this.items && this.items.length != items.length){ + arr.forEach(items, function(m){ + var id = this.getProperty(m, "id"); + arr.forEach(this.items, function(m2, i){ + if(this.getProperty(m2, "id") == id){ + this.items[i] = m2; + } + },this); + }, this); + items = this.items; + } + if(this.stretchToFit){ + this.displayRange = items.length; + } + this.onDataReceived(items); + this.items = items; + + + if(this.comparative){ + // all items are gathered together and used as one + // series so their properties can be compared. + var nm = "default"; + + this.seriesData[nm] = []; + this.seriesDataBk[nm] = []; + arr.forEach(items, function(m, i){ + var field = this.getProperty(m, this.fieldName); + this.seriesData[nm].push(field); + }, this); + + }else{ + + // each item is a seperate series. + arr.forEach(items, function(m, i){ + var nm = this.store.getLabel(m); + if(!this.seriesData[nm]){ + this.seriesData[nm] = []; + this.seriesDataBk[nm] = []; + } + + // the property in the item we are using + var field = this.getProperty(m, this.fieldName); + if(lang.isArray(field)){ + // Data is an array, so it's a snapshot, and not + // live, updating data + // + this.seriesData[nm] = field; + + }else{ + if(!this.scroll){ + // Data updates, and "moves in place". Columns and + // line markers go up and down + // + // create empty chart elements by starting an array + // with zeros until we reach our relevant data + var ar = arr.map(new Array(i+1), function(){ return 0; }); + ar.push(Number(field)); + this.seriesData[nm] = ar; + + }else{ + // Data updates and scrolls to the left + if(this.seriesDataBk[nm].length > this.seriesData[nm].length){ + this.seriesData[nm] = this.seriesDataBk[nm]; + } + // Collecting and storing series data. The items come in + // only one at a time, but we need to display historical + // data, so it is kept in memory. + this.seriesData[nm].push(Number(field)); + } + this.seriesDataBk[nm].push(Number(field)); + } + }, this); + } + + // displayData is the segment of the data array that is within + // the chart boundaries + var displayData; + if(this.firstRun){ + // First time around we need to add the series (chart lines) + // to the chart. + this.firstRun = false; + for(nm in this.seriesData){ + this.addSeries(nm, this.seriesData[nm]); + displayData = this.seriesData[nm]; + } + + }else{ + + // update existing series + for(nm in this.seriesData){ + displayData = this.seriesData[nm]; + + if(this.scroll && displayData.length > this.displayRange){ + // chart lines have gone beyond the right boundary. + this.dataOffset = displayData.length-this.displayRange - 1; + displayData = displayData.slice(displayData.length-this.displayRange, displayData.length); + } + this.updateSeries(nm, displayData); + } + } + this.dataLength = displayData.length; + + if(this.showing){ + this.render(); + } + + }, + + fetch: function(){ + // summary: + // Fetches initial data. Subsequent changes + // are received via onSet in data store. + // + if(!this.store){ return; } + this.store.fetch({query:this.query, queryOptions:this.queryOptions, start:this.start, count:this.count, sort:this.sort, + onComplete:lang.hitch(this, function(data){ + setTimeout(lang.hitch(this, function(){ + this.onData(data) + }),0); + }), + onError:lang.hitch(this, "onError") + }); + }, + + convertLabels: function(axis){ + // summary: + // Convenience method to convert a label array of strings + // into an array of objects + // + if(!axis.labels || lang.isObject(axis.labels[0])){ return null; } + + axis.labels = arr.map(axis.labels, function(ele, i){ + return {value:i, text:ele}; + }); + return null; // null + }, + + seriesLabels: function(/*Number*/val){ + // summary: + // Convenience method that sets series labels based on item labels. + val--; + if(this.series.length<1 || (!this.comparative && val>this.series.length)){ return "-"; } + if(this.comparative){ + return this.store.getLabel(this.items[val]);// String + + }else{ + // FIXME: + // Here we are setting the label base on if there is data in the array slot. + // A typical series may look like: [0,0,3.1,0,0,0] which mean the data is populated in the + // 3rd row or column. This works well and keeps the labels aligned but has a side effect + // of not showing the label is the data is zero. Work around is to not go lower than + // 0.01 or something. + for(var i=0;i<this.series.length; i++){ + if(this.series[i].data[val]>0){ + return this.series[i].name; // String + } + } + } + return "-"; // String + + }, + + resizeChart: function(/*Object*/dim){ + // summary: + // Call this function to change the chart size. + // Can be connected to a layout widget that calls + // resize. + // + var w = Math.max(dim.w, this.minWidth); + var h = Math.max(dim.h, this.minHeight); + this.resize(w, h); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/DataSeries.js b/js/dojo-1.7.2/dojox/charting/DataSeries.js new file mode 100644 index 0000000..190a264 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/DataSeries.js @@ -0,0 +1,184 @@ +//>>built +define("dojox/charting/DataSeries", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/_base/connect", "dojox/lang/functional"], + function(Lang, declare, ArrayUtil, Hub, df){ + + return declare("dojox.charting.DataSeries", null, { + constructor: function(store, kwArgs, value){ + // summary: + // Series adapter for dojo.data stores. + // store: Object: + // A dojo.data store object. + // kwArgs: Object: + // A store-specific keyword parameters used for fetching items. + // See dojo.data.api.Read.fetch(). + // value: Function|Object|String|Null: + // Function, which takes a store, and an object handle, and + // produces an output possibly inspecting the store's item. Or + // a dictionary object, which tells what names to extract from + // an object and how to map them to an output. Or a string, which + // is a numeric field name to use for plotting. If undefined, null + // or empty string (the default), "value" field is extracted. + this.store = store; + this.kwArgs = kwArgs; + + if(value){ + if(Lang.isFunction(value)){ + this.value = value; + }else if(Lang.isObject(value)){ + this.value = Lang.hitch(this, "_dictValue", + df.keys(value), value); + }else{ + this.value = Lang.hitch(this, "_fieldValue", value); + } + }else{ + this.value = Lang.hitch(this, "_defaultValue"); + } + + this.data = []; + + this._events = []; + + if(this.store.getFeatures()["dojo.data.api.Notification"]){ + this._events.push( + Hub.connect(this.store, "onNew", this, "_onStoreNew"), + Hub.connect(this.store, "onDelete", this, "_onStoreDelete"), + Hub.connect(this.store, "onSet", this, "_onStoreSet") + ); + } + + this.fetch(); + }, + + destroy: function(){ + // summary: + // Clean up before GC. + ArrayUtil.forEach(this._events, Hub.disconnect); + }, + + setSeriesObject: function(series){ + // summary: + // Sets a dojox.charting.Series object we will be working with. + // series: dojox.charting.Series: + // Our interface to the chart. + this.series = series; + }, + + // value transformers + + _dictValue: function(keys, dict, store, item){ + var o = {}; + ArrayUtil.forEach(keys, function(key){ + o[key] = store.getValue(item, dict[key]); + }); + return o; + }, + + _fieldValue: function(field, store, item){ + return store.getValue(item, field); + }, + + _defaultValue: function(store, item){ + return store.getValue(item, "value"); + }, + + // store fetch loop + + fetch: function(){ + // summary: + // Fetches data from the store and updates a chart. + if(!this._inFlight){ + this._inFlight = true; + var kwArgs = Lang.delegate(this.kwArgs); + kwArgs.onComplete = Lang.hitch(this, "_onFetchComplete"); + kwArgs.onError = Lang.hitch(this, "onFetchError"); + this.store.fetch(kwArgs); + } + }, + + _onFetchComplete: function(items, request){ + this.items = items; + this._buildItemMap(); + this.data = ArrayUtil.map(this.items, function(item){ + return this.value(this.store, item); + }, this); + this._pushDataChanges(); + this._inFlight = false; + }, + + onFetchError: function(errorData, request){ + // summary: + // As stub to process fetch errors. Provide so user can attach to + // it with dojo.connect(). See dojo.data.api.Read fetch() for + // details: onError property. + this._inFlight = false; + }, + + _buildItemMap: function(){ + if(this.store.getFeatures()["dojo.data.api.Identity"]){ + var itemMap = {}; + ArrayUtil.forEach(this.items, function(item, index){ + itemMap[this.store.getIdentity(item)] = index; + }, this); + this.itemMap = itemMap; + } + }, + + _pushDataChanges: function(){ + if(this.series){ + this.series.chart.updateSeries(this.series.name, this); + this.series.chart.delayedRender(); + } + }, + + // store notification handlers + + _onStoreNew: function(){ + // the only thing we can do is to re-fetch items + this.fetch(); + }, + + _onStoreDelete: function(item){ + // we cannot do anything with deleted item, the only way is to compare + // items for equality + if(this.items){ + var flag = ArrayUtil.some(this.items, function(it, index){ + if(it === item){ + this.items.splice(index, 1); + this._buildItemMap(); + this.data.splice(index, 1); + return true; + } + return false; + }, this); + if(flag){ + this._pushDataChanges(); + } + } + }, + + _onStoreSet: function(item){ + if(this.itemMap){ + // we can use our handy item map, if the store supports Identity + var id = this.store.getIdentity(item), index = this.itemMap[id]; + if(typeof index == "number"){ + this.data[index] = this.value(this.store, this.items[index]); + this._pushDataChanges(); + } + }else{ + // otherwise we have to rely on item's equality + if(this.items){ + var flag = ArrayUtil.some(this.items, function(it, index){ + if(it === item){ + this.data[index] = this.value(this.store, it); + return true; + } + return false; + }, this); + if(flag){ + this._pushDataChanges(); + } + } + } + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/Element.js b/js/dojo-1.7.2/dojox/charting/Element.js new file mode 100644 index 0000000..2f67b0e --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/Element.js @@ -0,0 +1,365 @@ +//>>built +define("dojox/charting/Element", ["dojo/_base/lang", "dojo/_base/array", "dojo/dom-construct","dojo/_base/declare", "dojox/gfx", "dojox/gfx/utils", "dojox/gfx/shape"], + function(lang, arr, domConstruct, declare, gfx, utils, shape){ + + return declare("dojox.charting.Element", null, { + // summary: + // A base class that is used to build other elements of a chart, such as + // a series. + // chart: dojox.charting.Chart + // The parent chart for this element. + // group: dojox.gfx.Group + // The visual GFX group representing this element. + // htmlElement: Array + // Any DOMNodes used as a part of this element (such as HTML-based labels). + // dirty: Boolean + // A flag indicating whether or not this element needs to be rendered. + + chart: null, + group: null, + htmlElements: null, + dirty: true, + + constructor: function(chart){ + // summary: + // Creates a new charting element. + // chart: dojox.charting.Chart + // The chart that this element belongs to. + this.chart = chart; + this.group = null; + this.htmlElements = []; + this.dirty = true; + this.trailingSymbol = "..."; + this._events = []; + }, + createGroup: function(creator){ + // summary: + // Convenience function to create a new dojox.gfx.Group. + // creator: dojox.gfx.Surface? + // An optional surface in which to create this group. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + if(!creator){ creator = this.chart.surface; } + if(!this.group){ + this.group = creator.createGroup(); + } + return this; // dojox.charting.Element + }, + purgeGroup: function(){ + // summary: + // Clear any elements out of our group, and destroy the group. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + this.destroyHtmlElements(); + if(this.group){ + // since 1.7.x we need dispose shape otherwise there is a memoryleak + utils.forEach(this.group, function(child){ + shape.dispose(child); + }); + this.group.clear(); + this.group.removeShape(); + this.group = null; + } + this.dirty = true; + if(this._events.length){ + arr.forEach(this._events, function(item){ + item.shape.disconnect(item.handle); + }); + this._events = []; + } + return this; // dojox.charting.Element + }, + cleanGroup: function(creator){ + // summary: + // Clean any elements (HTML or GFX-based) out of our group, and create a new one. + // creator: dojox.gfx.Surface? + // An optional surface to work with. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + this.destroyHtmlElements(); + if(!creator){ creator = this.chart.surface; } + if(this.group){ + this.group.clear(); + }else{ + this.group = creator.createGroup(); + } + this.dirty = true; + return this; // dojox.charting.Element + }, + destroyHtmlElements: function(){ + // summary: + // Destroy any DOMNodes that may have been created as a part of this element. + if(this.htmlElements.length){ + arr.forEach(this.htmlElements, domConstruct.destroy); + this.htmlElements = []; + } + }, + destroy: function(){ + // summary: + // API addition to conform to the rest of the Dojo Toolkit's standard. + this.purgeGroup(); + }, + //text utilities + getTextWidth: function(s, font){ + return gfx._base._getTextBox(s, {font: font}).w || 0; + }, + getTextWithLimitLength: function(s, font, limitWidth, truncated){ + // summary: + // Get the truncated string based on the limited width in px(dichotomy algorithm) + // s: String? + // candidate text. + // font: String? + // text's font style. + // limitWidth: Number? + // text limited width in px. + // truncated: Boolean? + // whether the input text(s) has already been truncated. + // returns: Object + // { + // text: processed text, maybe truncated or not + // truncated: whether text has been truncated + // } + if (!s || s.length <= 0) { + return { + text: "", + truncated: truncated || false + }; + } + if(!limitWidth || limitWidth <= 0){ + return { + text: s, + truncated: truncated || false + }; + } + var delta = 2, + //golden section for dichotomy algorithm + trucPercentage = 0.618, + minStr = s.substring(0,1) + this.trailingSymbol, + minWidth = this.getTextWidth(minStr, font); + if (limitWidth <= minWidth) { + return { + text: minStr, + truncated: true + }; + } + var width = this.getTextWidth(s, font); + if(width <= limitWidth){ + return { + text: s, + truncated: truncated || false + }; + }else{ + var begin = 0, + end = s.length; + while(begin < end){ + if(end - begin <= delta ){ + while (this.getTextWidth(s.substring(0, begin) + this.trailingSymbol, font) > limitWidth) { + begin -= 1; + } + return { + text: (s.substring(0,begin) + this.trailingSymbol), + truncated: true + }; + } + var index = begin + Math.round((end - begin) * trucPercentage), + widthIntercepted = this.getTextWidth(s.substring(0, index), font); + if(widthIntercepted < limitWidth){ + begin = index; + end = end; + }else{ + begin = begin; + end = index; + } + } + } + }, + getTextWithLimitCharCount: function(s, font, wcLimit, truncated){ + // summary: + // Get the truncated string based on the limited character count(dichotomy algorithm) + // s: String? + // candidate text. + // font: String? + // text's font style. + // wcLimit: Number? + // text limited character count. + // truncated: Boolean? + // whether the input text(s) has already been truncated. + // returns: Object + // { + // text: processed text, maybe truncated or not + // truncated: whether text has been truncated + // } + if (!s || s.length <= 0) { + return { + text: "", + truncated: truncated || false + }; + } + if(!wcLimit || wcLimit <= 0 || s.length <= wcLimit){ + return { + text: s, + truncated: truncated || false + }; + } + return { + text: s.substring(0, wcLimit) + this.trailingSymbol, + truncated: true + }; + }, + // fill utilities + _plotFill: function(fill, dim, offsets){ + // process a plot-wide fill + if(!fill || !fill.type || !fill.space){ + return fill; + } + var space = fill.space; + switch(fill.type){ + case "linear": + if(space === "plot" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultLinearGradient, fill); + fill.space = space; + // process dimensions + if(space === "plot" || space === "shapeX"){ + // process Y + var span = dim.height - offsets.t - offsets.b; + fill.y1 = offsets.t + span * fill.y1 / 100; + fill.y2 = offsets.t + span * fill.y2 / 100; + } + if(space === "plot" || space === "shapeY"){ + // process X + var span = dim.width - offsets.l - offsets.r; + fill.x1 = offsets.l + span * fill.x1 / 100; + fill.x2 = offsets.l + span * fill.x2 / 100; + } + } + break; + case "radial": + if(space === "plot"){ + // this one is used exclusively for scatter charts + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultRadialGradient, fill); + fill.space = space; + // process both dimensions + var spanX = dim.width - offsets.l - offsets.r, + spanY = dim.height - offsets.t - offsets.b; + fill.cx = offsets.l + spanX * fill.cx / 100; + fill.cy = offsets.t + spanY * fill.cy / 100; + fill.r = fill.r * Math.sqrt(spanX * spanX + spanY * spanY) / 200; + } + break; + case "pattern": + if(space === "plot" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultPattern, fill); + fill.space = space; + // process dimensions + if(space === "plot" || space === "shapeX"){ + // process Y + var span = dim.height - offsets.t - offsets.b; + fill.y = offsets.t + span * fill.y / 100; + fill.height = span * fill.height / 100; + } + if(space === "plot" || space === "shapeY"){ + // process X + var span = dim.width - offsets.l - offsets.r; + fill.x = offsets.l + span * fill.x / 100; + fill.width = span * fill.width / 100; + } + } + break; + } + return fill; + }, + _shapeFill: function(fill, bbox){ + // process shape-specific fill + if(!fill || !fill.space){ + return fill; + } + var space = fill.space; + switch(fill.type){ + case "linear": + if(space === "shape" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultLinearGradient, fill); + fill.space = space; + // process dimensions + if(space === "shape" || space === "shapeX"){ + // process X + var span = bbox.width; + fill.x1 = bbox.x + span * fill.x1 / 100; + fill.x2 = bbox.x + span * fill.x2 / 100; + } + if(space === "shape" || space === "shapeY"){ + // process Y + var span = bbox.height; + fill.y1 = bbox.y + span * fill.y1 / 100; + fill.y2 = bbox.y + span * fill.y2 / 100; + } + } + break; + case "radial": + if(space === "shape"){ + // this one is used exclusively for bubble charts and pie charts + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultRadialGradient, fill); + fill.space = space; + // process both dimensions + fill.cx = bbox.x + bbox.width / 2; + fill.cy = bbox.y + bbox.height / 2; + fill.r = fill.r * bbox.width / 200; + } + break; + case "pattern": + if(space === "shape" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultPattern, fill); + fill.space = space; + // process dimensions + if(space === "shape" || space === "shapeX"){ + // process X + var span = bbox.width; + fill.x = bbox.x + span * fill.x / 100; + fill.width = span * fill.width / 100; + } + if(space === "shape" || space === "shapeY"){ + // process Y + var span = bbox.height; + fill.y = bbox.y + span * fill.y / 100; + fill.height = span * fill.height / 100; + } + } + break; + } + return fill; + }, + _pseudoRadialFill: function(fill, center, radius, start, end){ + // process pseudo-radial fills + if(!fill || fill.type !== "radial" || fill.space !== "shape"){ + return fill; + } + // clone and normalize fill + var space = fill.space; + fill = gfx.makeParameters(gfx.defaultRadialGradient, fill); + fill.space = space; + if(arguments.length < 4){ + // process both dimensions + fill.cx = center.x; + fill.cy = center.y; + fill.r = fill.r * radius / 100; + return fill; + } + // convert to a linear gradient + var angle = arguments.length < 5 ? start : (end + start) / 2; + return { + type: "linear", + x1: center.x, + y1: center.y, + x2: center.x + fill.r * radius * Math.cos(angle) / 100, + y2: center.y + fill.r * radius * Math.sin(angle) / 100, + colors: fill.colors + }; + return fill; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/README b/js/dojo-1.7.2/dojox/charting/README new file mode 100644 index 0000000..0858f3a --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/README @@ -0,0 +1,31 @@ +------------------------------------------------------------------------------- +dojox.charting +------------------------------------------------------------------------------- +Version 0.800 +Release date: 10/31/2007 +------------------------------------------------------------------------------- +Project state: +beta +------------------------------------------------------------------------------- +Credits + Tom Trenka (ttrenka@gmail.com) + Eugene Lazutkin (eugene.lazutkin@gmail.com) +------------------------------------------------------------------------------- +Project description + +Implementation of simple charting library based on dojox.gfx/dojox.gfx3d. +------------------------------------------------------------------------------- +Dependencies: + +Dojo Core, dojox.gfx, dojox.gfx3d, dojox.lang. +------------------------------------------------------------------------------- +Documentation + +Not ready yet. +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/ +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/ +------------------------------------------------------------------------------- diff --git a/js/dojo-1.7.2/dojox/charting/Series.js b/js/dojo-1.7.2/dojox/charting/Series.js new file mode 100644 index 0000000..7a70bbd --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/Series.js @@ -0,0 +1,63 @@ +//>>built +define("dojox/charting/Series", ["dojo/_base/lang", "dojo/_base/declare", "./Element"], + function(lang, declare, Element){ + /*===== + dojox.charting.__SeriesCtorArgs = function(plot){ + // summary: + // An optional arguments object that can be used in the Series constructor. + // plot: String? + // The plot (by name) that this series belongs to. + this.plot = plot; + } + + var Element = dojox.charting.Element; + =====*/ + return declare("dojox.charting.Series", Element, { + // summary: + // An object representing a series of data for plotting on a chart. + constructor: function(chart, data, kwArgs){ + // summary: + // Create a new data series object for use within charting. + // chart: dojox.charting.Chart + // The chart that this series belongs to. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + // kwArgs: dojox.charting.__SeriesCtorArgs? + // An optional keyword arguments object to set details for this series. + lang.mixin(this, kwArgs); + if(typeof this.plot != "string"){ this.plot = "default"; } + this.update(data); + }, + + clear: function(){ + // summary: + // Clear the calculated additional parameters set on this series. + this.dyn = {}; + }, + + update: function(data){ + // summary: + // Set data and make this object dirty, so it can be redrawn. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + if(lang.isArray(data)){ + this.data = data; + }else{ + this.source = data; + this.data = this.source.data; + if(this.source.setSeriesObject){ + this.source.setSeriesObject(this); + } + } + this.dirty = true; + this.clear(); + } + }); + +}); diff --git a/js/dojo-1.7.2/dojox/charting/StoreSeries.js b/js/dojo-1.7.2/dojox/charting/StoreSeries.js new file mode 100644 index 0000000..d8fa9c9 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/StoreSeries.js @@ -0,0 +1,101 @@ +//>>built +define("dojox/charting/StoreSeries", ["dojo/_base/array", "dojo/_base/declare", "dojo/_base/Deferred"], + function(arr, declare, Deferred){ + + return declare("dojox.charting.StoreSeries", null, { + constructor: function(store, kwArgs, value){ + // summary: + // Series adapter for dojo object stores (dojo.store). + // store: Object: + // A dojo object store. + // kwArgs: Object: + // A store-specific keyword parameters used for querying objects. + // See dojo.store docs + // value: Function|Object|String|Null: + // Function, which takes an object handle, and + // produces an output possibly inspecting the store's item. Or + // a dictionary object, which tells what names to extract from + // an object and how to map them to an output. Or a string, which + // is a numeric field name to use for plotting. If undefined, null + // or empty string (the default), "value" field is extracted. + this.store = store; + this.kwArgs = kwArgs; + + if(value){ + if(typeof value == "function"){ + this.value = value; + }else if(typeof value == "object"){ + this.value = function(object){ + var o = {}; + for(var key in value){ + o[key] = object[value[key]]; + } + return o; + }; + }else{ + this.value = function(object){ + return object[value]; + }; + } + }else{ + this.value = function(object){ + return object.value; + }; + } + + this.data = []; + + this.fetch(); + }, + + destroy: function(){ + // summary: + // Clean up before GC. + if(this.observeHandle){ + this.observeHandle.dismiss(); + } + }, + + setSeriesObject: function(series){ + // summary: + // Sets a dojox.charting.Series object we will be working with. + // series: dojox.charting.Series: + // Our interface to the chart. + this.series = series; + }, + + // store fetch loop + + fetch: function(){ + // summary: + // Fetches data from the store and updates a chart. + var objects = this.objects = []; + var self = this; + if(this.observeHandle){ + this.observeHandle.dismiss(); + } + var results = this.store.query(this.kwArgs.query, this.kwArgs); + Deferred.when(results, function(objects){ + self.objects = objects; + update(); + }); + if(results.observe){ + this.observeHandle = results.observe(update, true); + } + function update(){ + self.data = arr.map(self.objects, function(object){ + return self.value(object, self.store); + }); + self._pushDataChanges(); + } + }, + + _pushDataChanges: function(){ + if(this.series){ + this.series.chart.updateSeries(this.series.name, this); + this.series.chart.delayedRender(); + } + } + + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/Theme.js b/js/dojo-1.7.2/dojox/charting/Theme.js new file mode 100644 index 0000000..ba09535 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/Theme.js @@ -0,0 +1,658 @@ +//>>built +define("dojox/charting/Theme", ["dojo/_base/lang", "dojo/_base/array","dojo/_base/declare","dojo/_base/Color", + "dojox/color/_base", "dojox/color/Palette", "dojox/lang/utils", "dojox/gfx/gradutils"], + function(lang, arr, declare, Color, colorX, Palette, dlu, dgg){ + + var Theme = declare("dojox.charting.Theme", null, { + // summary: + // A Theme is a pre-defined object, primarily JSON-based, that makes up the definitions to + // style a chart. + // + // description: + // While you can set up style definitions on a chart directly (usually through the various add methods + // on a dojox.charting.Chart object), a Theme simplifies this manual setup by allowing you to + // pre-define all of the various visual parameters of each element in a chart. + // + // Most of the properties of a Theme are straight-forward; if something is line-based (such as + // an axis or the ticks on an axis), they will be defined using basic stroke parameters. Likewise, + // if an element is primarily block-based (such as the background of a chart), it will be primarily + // fill-based. + // + // In addition (for convenience), a Theme definition does not have to contain the entire JSON-based + // structure. Each theme is built on top of a default theme (which serves as the basis for the theme + // "GreySkies"), and is mixed into the default theme object. This allows you to create a theme based, + // say, solely on colors for data series. + // + // Defining a new theme is relatively easy; see any of the themes in dojox.charting.themes for examples + // on how to define your own. + // + // When you set a theme on a chart, the theme itself is deep-cloned. This means that you cannot alter + // the theme itself after setting the theme value on a chart, and expect it to change your chart. If you + // are looking to make alterations to a theme for a chart, the suggestion would be to create your own + // theme, based on the one you want to use, that makes those alterations before it is applied to a chart. + // + // Finally, a Theme contains a number of functions to facilitate rendering operations on a chart--the main + // helper of which is the ~next~ method, in which a chart asks for the information for the next data series + // to be rendered. + // + // A note on colors: + // The Theme constructor was on the use of dojox.color.Palette (in general) for creating a visually distinct + // set of colors for usage in a chart. A palette is usually comprised of 5 different color definitions, and + // no more. If you have a need to render a chart with more than 5 data elements, you can simply "push" + // new color definitions into the theme's .color array. Make sure that you do that with the actual + // theme object from a Chart, and not in the theme itself (i.e. either do that before using .setTheme + // on a chart). + // + // example: + // The default theme (and structure) looks like so: + // | // all objects are structs used directly in dojox.gfx + // | chart:{ + // | stroke: null, + // | fill: "white", + // | pageStyle: null // suggested page style as an object suitable for dojo.style() + // | }, + // | plotarea:{ + // | stroke: null, + // | fill: "white" + // | }, + // | axis:{ + // | stroke: { // the axis itself + // | color: "#333", + // | width: 1 + // | }, + // | tick: { // used as a foundation for all ticks + // | color: "#666", + // | position: "center", + // | font: "normal normal normal 7pt Tahoma", // labels on axis + // | fontColor: "#333" // color of labels + // | }, + // | majorTick: { // major ticks on axis, and used for major gridlines + // | width: 1, + // | length: 6 + // | }, + // | minorTick: { // minor ticks on axis, and used for minor gridlines + // | width: 0.8, + // | length: 3 + // | }, + // | microTick: { // minor ticks on axis, and used for minor gridlines + // | width: 0.5, + // | length: 1 + // | } + // | }, + // | series: { + // | stroke: {width: 1.5, color: "#333"}, // line + // | outline: {width: 0.1, color: "#ccc"}, // outline + // | //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]}, + // | shadow: null, // no shadow + // | fill: "#ccc", // fill, if appropriate + // | font: "normal normal normal 8pt Tahoma", // if there's a label + // | fontColor: "#000" // color of labels + // | labelWiring: {width: 1, color: "#ccc"}, // connect marker and target data item(slice, column, bar...) + // | }, + // | marker: { // any markers on a series + // | symbol: "m-3,3 l3,-6 3,6 z", // symbol + // | stroke: {width: 1.5, color: "#333"}, // stroke + // | outline: {width: 0.1, color: "#ccc"}, // outline + // | shadow: null, // no shadow + // | fill: "#ccc", // fill if needed + // | font: "normal normal normal 8pt Tahoma", // label + // | fontColor: "#000" + // | }, + // | indicator: { + // | lineStroke: {width: 1.5, color: "#333"}, // line + // | lineOutline: {width: 0.1, color: "#ccc"}, // line outline + // | lineShadow: null, // no line shadow + // | stroke: {width: 1.5, color: "#333"}, // label background stroke + // | outline: {width: 0.1, color: "#ccc"}, // label background outline + // | shadow: null, // no label background shadow + // | fill: "#ccc", // label background fill + // | radius: 3, // radius of the label background + // | font: "normal normal normal 10pt Tahoma", // label font + // | fontColor: "#000" // label color + // | markerFill: "#ccc", // marker fill + // | markerSymbol: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", // marker symbol + // | markerStroke: {width: 1.5, color: "#333"}, // marker stroke + // | markerOutline: {width: 0.1, color: "#ccc"}, // marker outline + // | markerShadow: null, // no marker shadow + // | } + // + // example: + // Defining a new theme is pretty simple: + // | dojox.charting.themes.Grasslands = new dojox.charting.Theme({ + // | colors: [ "#70803a", "#dde574", "#788062", "#b1cc5d", "#eff2c2" ] + // | }); + // | + // | myChart.setTheme(dojox.charting.themes.Grasslands); + + shapeSpaces: {shape: 1, shapeX: 1, shapeY: 1}, + + constructor: function(kwArgs){ + // summary: + // Initialize a theme using the keyword arguments. Note that the arguments + // look like the example (above), and may include a few more parameters. + kwArgs = kwArgs || {}; + + // populate theme with defaults updating them if needed + var def = Theme.defaultTheme; + arr.forEach(["chart", "plotarea", "axis", "series", "marker", "indicator"], function(name){ + this[name] = lang.delegate(def[name], kwArgs[name]); + }, this); + + // personalize theme + if(kwArgs.seriesThemes && kwArgs.seriesThemes.length){ + this.colors = null; + this.seriesThemes = kwArgs.seriesThemes.slice(0); + }else{ + this.seriesThemes = null; + this.colors = (kwArgs.colors || Theme.defaultColors).slice(0); + } + this.markerThemes = null; + if(kwArgs.markerThemes && kwArgs.markerThemes.length){ + this.markerThemes = kwArgs.markerThemes.slice(0); + } + this.markers = kwArgs.markers ? lang.clone(kwArgs.markers) : lang.delegate(Theme.defaultMarkers); + + // set flags + this.noGradConv = kwArgs.noGradConv; + this.noRadialConv = kwArgs.noRadialConv; + if(kwArgs.reverseFills){ + this.reverseFills(); + } + + // private housekeeping + this._current = 0; + this._buildMarkerArray(); + }, + + clone: function(){ + // summary: + // Clone the current theme. + // returns: dojox.charting.Theme + // The cloned theme; any alterations made will not affect the original. + var theme = new Theme({ + // theme components + chart: this.chart, + plotarea: this.plotarea, + axis: this.axis, + series: this.series, + marker: this.marker, + // individual arrays + colors: this.colors, + markers: this.markers, + indicator: this.indicator, + seriesThemes: this.seriesThemes, + markerThemes: this.markerThemes, + // flags + noGradConv: this.noGradConv, + noRadialConv: this.noRadialConv + }); + // copy custom methods + arr.forEach( + ["clone", "clear", "next", "skip", "addMixin", "post", "getTick"], + function(name){ + if(this.hasOwnProperty(name)){ + theme[name] = this[name]; + } + }, + this + ); + return theme; // dojox.charting.Theme + }, + + clear: function(){ + // summary: + // Clear and reset the internal pointer to start fresh. + this._current = 0; + }, + + next: function(elementType, mixin, doPost){ + // summary: + // Get the next color or series theme. + // elementType: String? + // An optional element type (for use with series themes) + // mixin: Object? + // An optional object to mix into the theme. + // doPost: Boolean? + // A flag to post-process the results. + // returns: Object + // An object of the structure { series, marker, symbol } + var merge = dlu.merge, series, marker; + if(this.colors){ + series = lang.delegate(this.series); + marker = lang.delegate(this.marker); + var color = new Color(this.colors[this._current % this.colors.length]), old; + // modify the stroke + if(series.stroke && series.stroke.color){ + series.stroke = lang.delegate(series.stroke); + old = new Color(series.stroke.color); + series.stroke.color = new Color(color); + series.stroke.color.a = old.a; + }else{ + series.stroke = {color: color}; + } + if(marker.stroke && marker.stroke.color){ + marker.stroke = lang.delegate(marker.stroke); + old = new Color(marker.stroke.color); + marker.stroke.color = new Color(color); + marker.stroke.color.a = old.a; + }else{ + marker.stroke = {color: color}; + } + // modify the fill + if(!series.fill || series.fill.type){ + series.fill = color; + }else{ + old = new Color(series.fill); + series.fill = new Color(color); + series.fill.a = old.a; + } + if(!marker.fill || marker.fill.type){ + marker.fill = color; + }else{ + old = new Color(marker.fill); + marker.fill = new Color(color); + marker.fill.a = old.a; + } + }else{ + series = this.seriesThemes ? + merge(this.series, this.seriesThemes[this._current % this.seriesThemes.length]) : + this.series; + marker = this.markerThemes ? + merge(this.marker, this.markerThemes[this._current % this.markerThemes.length]) : + series; + } + + var symbol = marker && marker.symbol || this._markers[this._current % this._markers.length]; + + var theme = {series: series, marker: marker, symbol: symbol}; + + // advance the counter + ++this._current; + + if(mixin){ + theme = this.addMixin(theme, elementType, mixin); + } + if(doPost){ + theme = this.post(theme, elementType); + } + + return theme; // Object + }, + + skip: function(){ + // summary: + // Skip the next internal color. + ++this._current; + }, + + addMixin: function(theme, elementType, mixin, doPost){ + // summary: + // Add a mixin object to the passed theme and process. + // theme: dojox.charting.Theme + // The theme to mixin to. + // elementType: String + // The type of element in question. Can be "line", "bar" or "circle" + // mixin: Object|Array + // The object or objects to mix into the theme. + // doPost: Boolean + // If true, run the new theme through the post-processor. + // returns: dojox.charting.Theme + // The new theme. + if(lang.isArray(mixin)){ + arr.forEach(mixin, function(m){ + theme = this.addMixin(theme, elementType, m); + }, this); + }else{ + var t = {}; + if("color" in mixin){ + if(elementType == "line" || elementType == "area"){ + lang.setObject("series.stroke.color", mixin.color, t); + lang.setObject("marker.stroke.color", mixin.color, t); + }else{ + lang.setObject("series.fill", mixin.color, t); + } + } + arr.forEach(["stroke", "outline", "shadow", "fill", "font", "fontColor", "labelWiring"], function(name){ + var markerName = "marker" + name.charAt(0).toUpperCase() + name.substr(1), + b = markerName in mixin; + if(name in mixin){ + lang.setObject("series." + name, mixin[name], t); + if(!b){ + lang.setObject("marker." + name, mixin[name], t); + } + } + if(b){ + lang.setObject("marker." + name, mixin[markerName], t); + } + }); + if("marker" in mixin){ + t.symbol = mixin.marker; + } + theme = dlu.merge(theme, t); + } + if(doPost){ + theme = this.post(theme, elementType); + } + return theme; // dojox.charting.Theme + }, + + post: function(theme, elementType){ + // summary: + // Process any post-shape fills. + // theme: dojox.charting.Theme + // The theme to post process with. + // elementType: String + // The type of element being filled. Can be "bar" or "circle". + // returns: dojox.charting.Theme + // The post-processed theme. + var fill = theme.series.fill, t; + if(!this.noGradConv && this.shapeSpaces[fill.space] && fill.type == "linear"){ + if(elementType == "bar"){ + // transpose start and end points + t = { + x1: fill.y1, + y1: fill.x1, + x2: fill.y2, + y2: fill.x2 + }; + }else if(!this.noRadialConv && fill.space == "shape" && (elementType == "slice" || elementType == "circle")){ + // switch to radial + t = { + type: "radial", + cx: 0, + cy: 0, + r: 100 + }; + } + if(t){ + return dlu.merge(theme, {series: {fill: t}}); + } + } + return theme; // dojox.charting.Theme + }, + + getTick: function(name, mixin){ + // summary: + // Calculates and merges tick parameters. + // name: String + // Tick name, can be "major", "minor", or "micro". + // mixin: Object? + // Optional object to mix in to the tick. + var tick = this.axis.tick, tickName = name + "Tick", + merge = dlu.merge; + if(tick){ + if(this.axis[tickName]){ + tick = merge(tick, this.axis[tickName]); + } + }else{ + tick = this.axis[tickName]; + } + if(mixin){ + if(tick){ + if(mixin[tickName]){ + tick = merge(tick, mixin[tickName]); + } + }else{ + tick = mixin[tickName]; + } + } + return tick; // Object + }, + + inspectObjects: function(f){ + arr.forEach(["chart", "plotarea", "axis", "series", "marker", "indicator"], function(name){ + f(this[name]); + }, this); + if(this.seriesThemes){ + arr.forEach(this.seriesThemes, f); + } + if(this.markerThemes){ + arr.forEach(this.markerThemes, f); + } + }, + + reverseFills: function(){ + this.inspectObjects(function(o){ + if(o && o.fill){ + o.fill = dgg.reverse(o.fill); + } + }); + }, + + addMarker:function(/*String*/ name, /*String*/ segment){ + // summary: + // Add a custom marker to this theme. + // example: + // | myTheme.addMarker("Ellipse", foo); + this.markers[name] = segment; + this._buildMarkerArray(); + }, + + setMarkers:function(/*Object*/ obj){ + // summary: + // Set all the markers of this theme at once. obj should be a + // dictionary of keys and path segments. + // + // example: + // | myTheme.setMarkers({ "CIRCLE": foo }); + this.markers = obj; + this._buildMarkerArray(); + }, + + _buildMarkerArray: function(){ + this._markers = []; + for(var p in this.markers){ + this._markers.push(this.markers[p]); + } + } +}); + +/*===== +dojox.charting.Theme.__DefineColorArgs = function(num, colors, hue, saturation, low, high, base, generator){ + // summary: + // The arguments object that can be passed to define colors for a theme. + // num: Number? + // The number of colors to generate. Defaults to 5. + // colors: String[]|dojo.Color[]? + // A pre-defined set of colors; this is passed through to the Theme directly. + // hue: Number? + // A hue to base the generated colors from (a number from 0 - 359). + // saturation: Number? + // If a hue is passed, this is used for the saturation value (0 - 100). + // low: Number? + // An optional value to determine the lowest value used to generate a color (HSV model) + // high: Number? + // An optional value to determine the highest value used to generate a color (HSV model) + // base: String|dojo.Color? + // A base color to use if we are defining colors using dojox.color.Palette + // generator: String? + // The generator function name from dojox.color.Palette. + this.num = num; + this.colors = colors; + this.hue = hue; + this.saturation = saturation; + this.low = low; + this.high = high; + this.base = base; + this.generator = generator; +} +=====*/ +lang.mixin(Theme, { + defaultMarkers: { + CIRCLE: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", + SQUARE: "m-3,-3 l0,6 6,0 0,-6 z", + DIAMOND: "m0,-3 l3,3 -3,3 -3,-3 z", + CROSS: "m0,-3 l0,6 m-3,-3 l6,0", + X: "m-3,-3 l6,6 m0,-6 l-6,6", + TRIANGLE: "m-3,3 l3,-6 3,6 z", + TRIANGLE_INVERTED: "m-3,-3 l3,6 3,-6 z" + }, + + defaultColors:[ + // gray skies + "#54544c", "#858e94", "#6e767a", "#948585", "#474747" + ], + + defaultTheme: { + // all objects are structs used directly in dojox.gfx + chart:{ + stroke: null, + fill: "white", + pageStyle: null, + titleGap: 20, + titlePos: "top", + titleFont: "normal normal bold 14pt Tahoma", // labels on axis + titleFontColor: "#333" + }, + plotarea:{ + stroke: null, + fill: "white" + }, + // TODO: label rotation on axis + axis:{ + stroke: { // the axis itself + color: "#333", + width: 1 + }, + tick: { // used as a foundation for all ticks + color: "#666", + position: "center", + font: "normal normal normal 7pt Tahoma", // labels on axis + fontColor: "#333", // color of labels + titleGap: 15, + titleFont: "normal normal normal 11pt Tahoma", // labels on axis + titleFontColor: "#333", // color of labels + titleOrientation: "axis" // "axis": facing the axis, "away": facing away + }, + majorTick: { // major ticks on axis, and used for major gridlines + width: 1, + length: 6 + }, + minorTick: { // minor ticks on axis, and used for minor gridlines + width: 0.8, + length: 3 + }, + microTick: { // minor ticks on axis, and used for minor gridlines + width: 0.5, + length: 1 + } + }, + series: { + // used as a "main" theme for series, sThemes augment it + stroke: {width: 1.5, color: "#333"}, // line + outline: {width: 0.1, color: "#ccc"}, // outline + //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]}, + shadow: null, // no shadow + fill: "#ccc", // fill, if appropriate + font: "normal normal normal 8pt Tahoma", // if there's a label + fontColor: "#000", // color of labels + labelWiring: {width: 1, color: "#ccc"} // connect marker and target data item(slice, column, bar...) + }, + marker: { // any markers on a series + stroke: {width: 1.5, color: "#333"}, // stroke + outline: {width: 0.1, color: "#ccc"}, // outline + //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]}, + shadow: null, // no shadow + fill: "#ccc", // fill if needed + font: "normal normal normal 8pt Tahoma", // label + fontColor: "#000" + }, + indicator: { + lineStroke: {width: 1.5, color: "#333"}, + lineOutline: {width: 0.1, color: "#ccc"}, + lineShadow: null, + stroke: {width: 1.5, color: "#333"}, + outline: {width: 0.1, color: "#ccc"}, + shadow: null, + fill : "#ccc", + radius: 3, + font: "normal normal normal 10pt Tahoma", + fontColor: "#000", + markerFill: "#ccc", + markerSymbol: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", + markerStroke: {width: 1.5, color: "#333"}, + markerOutline: {width: 0.1, color: "#ccc"}, + markerShadow: null + } + }, + + defineColors: function(kwArgs){ + // summary: + // Generate a set of colors for the theme based on keyword + // arguments. + // kwArgs: dojox.charting.Theme.__DefineColorArgs + // The arguments object used to define colors. + // returns: dojo.Color[] + // An array of colors for use in a theme. + // + // example: + // | var colors = dojox.charting.Theme.defineColors({ + // | base: "#369", + // | generator: "compound" + // | }); + // + // example: + // | var colors = dojox.charting.Theme.defineColors({ + // | hue: 60, + // | saturation: 90, + // | low: 30, + // | high: 80 + // | }); + kwArgs = kwArgs || {}; + var l, c = [], n = kwArgs.num || 5; // the number of colors to generate + if(kwArgs.colors){ + // we have an array of colors predefined, so fix for the number of series. + l = kwArgs.colors.length; + for(var i = 0; i < n; i++){ + c.push(kwArgs.colors[i % l]); + } + return c; // dojo.Color[] + } + if(kwArgs.hue){ + // single hue, generate a set based on brightness + var s = kwArgs.saturation || 100, // saturation + st = kwArgs.low || 30, + end = kwArgs.high || 90; + // we'd like it to be a little on the darker side. + l = (end + st) / 2; + // alternately, use "shades" + return colorX.Palette.generate( + colorX.fromHsv(kwArgs.hue, s, l), "monochromatic" + ).colors; + } + if(kwArgs.generator){ + // pass a base color and the name of a generator + return colorX.Palette.generate(kwArgs.base, kwArgs.generator).colors; + } + return c; // dojo.Color[] + }, + + generateGradient: function(fillPattern, colorFrom, colorTo){ + var fill = lang.delegate(fillPattern); + fill.colors = [ + {offset: 0, color: colorFrom}, + {offset: 1, color: colorTo} + ]; + return fill; + }, + + generateHslColor: function(color, luminance){ + color = new Color(color); + var hsl = color.toHsl(), + result = colorX.fromHsl(hsl.h, hsl.s, luminance); + result.a = color.a; // add missing opacity + return result; + }, + + generateHslGradient: function(color, fillPattern, lumFrom, lumTo){ + color = new Color(color); + var hsl = color.toHsl(), + colorFrom = colorX.fromHsl(hsl.h, hsl.s, lumFrom), + colorTo = colorX.fromHsl(hsl.h, hsl.s, lumTo); + colorFrom.a = colorTo.a = color.a; // add missing opacity + return Theme.generateGradient(fillPattern, colorFrom, colorTo); // Object + } +}); + +return Theme; +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/Base.js b/js/dojo-1.7.2/dojox/charting/action2d/Base.js new file mode 100644 index 0000000..9f57e25 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/Base.js @@ -0,0 +1,37 @@ +//>>built +define("dojox/charting/action2d/Base", ["dojo/_base/lang", "dojo/_base/declare"], + function(lang, declare){ + + return declare("dojox.charting.action2d.Base", null, { + // summary: + // Base action class for plot and chart actions. + + constructor: function(chart, plot){ + // summary: + // Create a new base action. This can either be a plot or a chart action. + // chart: dojox.charting.Chart + // The chart this action applies to. + // plot: String?|dojox.charting.plot2d.Base? + // Optional target plot for this action. Default is "default". + this.chart = chart; + this.plot = plot ? (lang.isString(plot) ? this.chart.getPlot(plot) : plot) : this.chart.getPlot("default"); + }, + + connect: function(){ + // summary: + // Connect this action to the plot or the chart. + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the plot or the chart. + }, + + destroy: function(){ + // summary: + // Do any cleanup needed when destroying parent elements. + this.disconnect(); + } + }); + +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/ChartAction.js b/js/dojo-1.7.2/dojox/charting/action2d/ChartAction.js new file mode 100644 index 0000000..a46d86f --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/ChartAction.js @@ -0,0 +1,39 @@ +//>>built +define("dojox/charting/action2d/ChartAction", ["dojo/_base/connect", "dojo/_base/declare", "./Base"], + function(hub, declare, Base){ + /*===== + var Base = dojox.charting.action2d.Base; + =====*/ + return declare("dojox.charting.action2d.ChartAction", Base, { + // summary: + // Base action class for chart actions. + + constructor: function(chart, plot){ + // summary: + // Create a new base chart action. + // chart: dojox.charting.Chart + // The chart this action applies to. + // plot: String?|dojox.charting.plot2d.Base? + // Optional target plot for this chart action. Default is "default". + }, + + connect: function(){ + // summary: + // Connect this action to the chart. + for(var i = 0; i < this._listeners.length; ++i){ + this._listeners[i].handle = hub.connect(this.chart.node, this._listeners[i].eventName, + this, this._listeners[i].methodName); + } + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the chart. + for(var i = 0; i < this._listeners.length; ++i){ + hub.disconnect(this._listeners[i].handle); + delete this._listeners[i].handle; + } + } +}); + +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/Highlight.js b/js/dojo-1.7.2/dojox/charting/action2d/Highlight.js new file mode 100644 index 0000000..8656a7b --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/Highlight.js @@ -0,0 +1,127 @@ +//>>built +define("dojox/charting/action2d/Highlight", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/Color", "dojo/_base/connect", "dojox/color/_base", + "./PlotAction", "dojo/fx/easing", "dojox/gfx/fx"], + function(dojo, lang, declare, Color, hub, c, PlotAction, dfe, dgf){ + + /*===== + dojo.declare("dojox.charting.action2d.__HighlightCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // highlight: String|dojo.Color|Function? + // Either a color or a function that creates a color when highlighting happens. + highlight: null + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SATURATION = 100, // % + DEFAULT_LUMINOSITY1 = 75, // % + DEFAULT_LUMINOSITY2 = 50, // % + cc = function(color){ + return function(){ return color; }; + }, + + hl = function(color){ + var a = new c.Color(color), + x = a.toHsl(); + if(x.s == 0){ + x.l = x.l < 50 ? 100 : 0; + }else{ + x.s = DEFAULT_SATURATION; + if(x.l < DEFAULT_LUMINOSITY2){ + x.l = DEFAULT_LUMINOSITY1; + }else if(x.l > DEFAULT_LUMINOSITY1){ + x.l = DEFAULT_LUMINOSITY2; + }else{ + x.l = x.l - DEFAULT_LUMINOSITY2 > DEFAULT_LUMINOSITY1 - x.l ? + DEFAULT_LUMINOSITY2 : DEFAULT_LUMINOSITY1; + } + } + return c.fromHsl(x); + }; + + return declare("dojox.charting.action2d.Highlight", PlotAction, { + // summary: + // Creates a highlighting action on a plot, where an element on that plot + // has a highlight on it. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut // easing for the action + }, + optionalParams: { + highlight: "red" // name for the highlight color + // programmatic instantiation can use functions and color objects + }, + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the highlighting action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: charting.action2d.__HighlightCtorArgs? + // Optional keyword arguments object for setting parameters. + var a = kwArgs && kwArgs.highlight; + this.colorFun = a ? (lang.isFunction(a) ? a : cc(a)) : hl; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the highlighting action. + if(!o.shape || !(o.type in this.overOutEvents)){ return; } + + var runName = o.run.name, index = o.index, anim, startFill, endFill; + + if(runName in this.anim){ + anim = this.anim[runName][index]; + }else{ + this.anim[runName] = {}; + } + + if(anim){ + anim.action.stop(true); + }else{ + var color = o.shape.getFill(); + if(!color || !(color instanceof Color)){ + return; + } + this.anim[runName][index] = anim = { + start: color, + end: this.colorFun(color) + }; + } + + var start = anim.start, end = anim.end; + if(o.type == "onmouseout"){ + // swap colors + var t = start; + start = end; + end = t; + } + + anim.action = dgf.animateFill({ + shape: o.shape, + duration: this.duration, + easing: this.easing, + color: {start: start, end: end} + }); + if(o.type == "onmouseout"){ + hub.connect(anim.action, "onEnd", this, function(){ + if(this.anim[runName]){ + delete this.anim[runName][index]; + } + }); + } + anim.action.play(); + } + }); + +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/Magnify.js b/js/dojo-1.7.2/dojox/charting/action2d/Magnify.js new file mode 100644 index 0000000..c59c143 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/Magnify.js @@ -0,0 +1,117 @@ +//>>built +define("dojox/charting/action2d/Magnify", ["dojo/_base/connect", "dojo/_base/declare", + "./PlotAction", "dojox/gfx/matrix", + "dojox/gfx/fx", "dojo/fx", "dojo/fx/easing"], + function(Hub, declare, PlotAction, m, gf, df, dfe){ + + /*===== + dojo.declare("dojox.charting.action2d.__MagnifyCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // scale: Number? + // The amount to magnify the given object to. Default is 2. + scale: 2 + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SCALE = 2; + + return declare("dojox.charting.action2d.Magnify", PlotAction, { + // summary: + // Create an action that magnifies the object the action is applied to. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut, // easing for the action + scale: DEFAULT_SCALE // scale of magnification + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the magnifying action. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot to apply the action to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__MagnifyCtorArgs? + // Optional keyword arguments for this action. + + // process optional named parameters + this.scale = kwArgs && typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the magnifying action. + if(!o.shape || !(o.type in this.overOutEvents) || + !("cx" in o) || !("cy" in o)){ return; } + + var runName = o.run.name, index = o.index, vector = [], anim, init, scale; + + if(runName in this.anim){ + anim = this.anim[runName][index]; + }else{ + this.anim[runName] = {}; + } + + if(anim){ + anim.action.stop(true); + }else{ + this.anim[runName][index] = anim = {}; + } + + if(o.type == "onmouseover"){ + init = m.identity; + scale = this.scale; + }else{ + init = m.scaleAt(this.scale, o.cx, o.cy); + scale = 1 / this.scale; + } + + var kwArgs = { + shape: o.shape, + duration: this.duration, + easing: this.easing, + transform: [ + {name: "scaleAt", start: [1, o.cx, o.cy], end: [scale, o.cx, o.cy]}, + init + ] + }; + if(o.shape){ + vector.push(gf.animateTransform(kwArgs)); + } + if(o.oultine){ + kwArgs.shape = o.outline; + vector.push(gf.animateTransform(kwArgs)); + } + if(o.shadow){ + kwArgs.shape = o.shadow; + vector.push(gf.animateTransform(kwArgs)); + } + + if(!vector.length){ + delete this.anim[runName][index]; + return; + } + + anim.action = df.combine(vector); + if(o.type == "onmouseout"){ + Hub.connect(anim.action, "onEnd", this, function(){ + if(this.anim[runName]){ + delete this.anim[runName][index]; + } + }); + } + anim.action.play(); + } + }); + +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/MouseIndicator.js b/js/dojo-1.7.2/dojox/charting/action2d/MouseIndicator.js new file mode 100644 index 0000000..b6cd8fe --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/MouseIndicator.js @@ -0,0 +1,222 @@ +//>>built +define("dojox/charting/action2d/MouseIndicator", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/window", "dojo/_base/sniff", + "./ChartAction", "./_IndicatorElement", "dojox/lang/utils", "dojo/_base/event","dojo/_base/array"], + function(lang, declare, hub, win, has, ChartAction, IndicatorElement, du, eventUtil, arr){ + + /*===== + dojo.declare("dojox.charting.action2d.__MouseIndicatorCtorArgs", null, { + // summary: + // Additional arguments for mouse indicator. + + // series: String + // Target series name for this action. + series: "", + + // autoScroll: Boolean? + // Whether when moving indicator the chart is automatically scrolled. Default is true. + autoScroll: true, + + // vertical: Boolean? + // Whether the indicator is vertical or not. Default is true. + vertical: true, + + // fixed: Boolean? + // Whether a fixed precision must be applied to data values for display. Default is true. + fixed: true, + + // precision: Number? + // The precision at which to round data values for display. Default is 1. + precision: 0, + + // lineStroke: dojo.gfx.Stroke? + // An optional stroke to use for indicator line. + lineStroke: {}, + + // lineOutline: dojo.gfx.Stroke? + // An optional outline to use for indicator line. + lineOutline: {}, + + // lineShadow: dojo.gfx.Stroke? + // An optional shadow to use for indicator line. + lineShadow: {}, + + // stroke: dojo.gfx.Stroke? + // An optional stroke to use for indicator label background. + stroke: {}, + + // outline: dojo.gfx.Stroke? + // An optional outline to use for indicator label background. + outline: {}, + + // shadow: dojo.gfx.Stroke? + // An optional shadow to use for indicator label background. + shadow: {}, + + // fill: dojo.gfx.Fill? + // An optional fill to use for indicator label background. + fill: {}, + + // fillFunc: Function? + // An optional function to use to compute label background fill. It takes precedence over + // fill property when available. + fillFunc: null, + + // labelFunc: Function? + // An optional function to use to compute label text. It takes precedence over + // the default text when available. + labelFunc: {}, + + // font: String? + // A font definition to use for indicator label background. + font: "", + + // fontColor: String|dojo.Color? + // The color to use for indicator label background. + fontColor: "", + + // markerStroke: dojo.gfx.Stroke? + // An optional stroke to use for indicator marker. + markerStroke: {}, + + // markerOutline: dojo.gfx.Stroke? + // An optional outline to use for indicator marker. + markerOutline: {}, + + // markerShadow: dojo.gfx.Stroke? + // An optional shadow to use for indicator marker. + markerShadow: {}, + + // markerFill: dojo.gfx.Fill? + // An optional fill to use for indicator marker. + markerFill: {}, + + // markerSymbol: String? + // An optional symbol string to use for indicator marker. + markerFill: {} + }); + var ChartAction = dojox.charting.action2d.ChartAction; + =====*/ + + return declare("dojox.charting.action2d.MouseIndicator", ChartAction, { + // summary: + // Create a mouse indicator action. You can drag mouse over the chart to display a data indicator. + + // the data description block for the widget parser + defaultParams: { + series: "", + vertical: true, + autoScroll: true, + fixed: true, + precision: 0 + }, + optionalParams: { + lineStroke: {}, + outlineStroke: {}, + shadowStroke: {}, + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + fillFunc: null, + labelFunc: null, + font: "", + fontColor: "", + markerStroke: {}, + markerOutline: {}, + markerShadow: {}, + markerFill: {}, + markerSymbol: "" + }, + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create an mouse indicator action and connect it. + // chart: dojox.charting.Chart + // The chart this action applies to. + // kwArgs: dojox.charting.action2d.__MouseIndicatorCtorArgs? + // Optional arguments for the chart action. + this._listeners = [{eventName: "onmousedown", methodName: "onMouseDown"}]; + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this._uName = "mouseIndicator"+this.opt.series; + this._handles = []; + this.connect(); + }, + + _disconnectHandles: function(){ + if(has("ie")){ + this.chart.node.releaseCapture(); + } + arr.forEach(this._handles, hub.disconnect); + this._handles = []; + }, + + connect: function(){ + // summary: + // Connect this action to the chart. This adds a indicator plot + // to the chart that's why Chart.render() must be called after connect. + this.inherited(arguments); + // add plot with unique name + this.chart.addPlot(this._uName, {type: IndicatorElement, inter: this}); + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the chart. + if(this._isMouseDown){ + this.onMouseUp(); + } + this.chart.removePlot(this._uName); + this.inherited(arguments); + this._disconnectHandles(); + }, + + onMouseDown: function(event){ + // summary: + // Called when mouse is down on the chart. + this._isMouseDown = true; + + // we now want to capture mouse move events everywhere to avoid + // stop scrolling when going out of the chart window + if(has("ie")){ + this._handles.push(hub.connect(this.chart.node, "onmousemove", this, "onMouseMove")); + this._handles.push(hub.connect(this.chart.node, "onmouseup", this, "onMouseUp")); + this.chart.node.setCapture(); + }else{ + this._handles.push(hub.connect(win.doc, "onmousemove", this, "onMouseMove")); + this._handles.push(hub.connect(win.doc, "onmouseup", this, "onMouseUp")); + } + + this._onMouseSingle(event); + }, + + onMouseMove: function(event){ + // summary: + // Called when the mouse is moved on the chart. + if(this._isMouseDown){ + this._onMouseSingle(event); + } + }, + + _onMouseSingle: function(event){ + var plot = this.chart.getPlot(this._uName); + plot.pageCoord = {x: event.pageX, y: event.pageY}; + plot.dirty = true; + this.chart.render(); + eventUtil.stop(event); + }, + + onMouseUp: function(event){ + // summary: + // Called when mouse is up on the chart. + var plot = this.chart.getPlot(this._uName); + plot.stopTrack(); + this._isMouseDown = false; + this._disconnectHandles(); + plot.pageCoord = null; + plot.dirty = true; + this.chart.render(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/MouseZoomAndPan.js b/js/dojo-1.7.2/dojox/charting/action2d/MouseZoomAndPan.js new file mode 100644 index 0000000..eea708b --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/MouseZoomAndPan.js @@ -0,0 +1,246 @@ +//>>built +define("dojox/charting/action2d/MouseZoomAndPan", ["dojo/_base/html", "dojo/_base/declare", "dojo/_base/window", "dojo/_base/array", "dojo/_base/event", + "dojo/_base/connect", "./ChartAction", "dojo/_base/sniff", "dojo/dom-prop", "dojo/keys"], + function(html, declare, win, arr, eventUtil, connect, ChartAction, has, domProp, keys){ + + /*===== + dojo.declare("dojox.charting.action2d.__MouseZoomAndPanCtorArgs", null, { + // summary: + // Additional arguments for mouse zoom and pan actions. + + // axis: String? + // Target axis name for this action. Default is "x". + axis: "x", + // scaleFactor: Number? + // The scale factor applied on mouse wheel zoom. Default is 1.2. + scaleFactor: 1.2, + // maxScale: Number? + // The max scale factor accepted by this chart action. Default is 100. + maxScale: 100, + // enableScroll: Boolean? + // Whether mouse drag gesture should scroll the chart. Default is true. + enableScroll: true, + // enableDoubleClickZoom: Boolean? + // Whether a double click gesture should toggle between fit and zoom on the chart. Default is true. + enableDoubleClickZoom: true, + // enableKeyZoom: Boolean? + // Whether a keyZoomModifier + + or keyZoomModifier + - key press should zoom in our out on the chart. Default is true. + enableKeyZoom: true, + // keyZoomModifier: String? + // Which keyboard modifier should used for keyboard zoom in and out. This should be one of "alt", "ctrl", "shift" or "none" for no modifier. Default is "ctrl". + keyZoomModifier: "ctrl" + }); + var ChartAction = dojox.charting.action2d.ChartAction; + =====*/ + + var sUnit = has("mozilla") ? -3 : 120; + var keyTests = { + none: function(event){ + return !event.ctrlKey && !event.altKey && !event.shiftKey; + }, + ctrl: function(event){ + return event.ctrlKey && !event.altKey && !event.shiftKey; + }, + alt: function(event){ + return !event.ctrlKey && event.altKey && !event.shiftKey; + }, + shift: function(event){ + return !event.ctrlKey && !event.altKey && event.shiftKey; + } + }; + + return declare("dojox.charting.action2d.MouseZoomAndPan", ChartAction, { + // summary: + // Create an mouse zoom and pan action. + // You can zoom in or out the data window with mouse wheel. You can scroll using mouse drag gesture. + // You can toggle between zoom and fit view using double click on the chart. + + // the data description block for the widget parser + defaultParams: { + axis: "x", + scaleFactor: 1.2, + maxScale: 100, + enableScroll: true, + enableDoubleClickZoom: true, + enableKeyZoom: true, + keyZoomModifier: "ctrl" + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create an mouse zoom and pan action and connect it. + // chart: dojox.charting.Chart + // The chart this action applies to. + // kwArgs: dojox.charting.action2d.__MouseZoomAndPanCtorArgs? + // Optional arguments for the chart action. + this._listeners = [{eventName: !has("mozilla") ? "onmousewheel" : "DOMMouseScroll", methodName: "onMouseWheel"}]; + if(!kwArgs){ kwArgs = {}; } + this.axis = kwArgs.axis ? kwArgs.axis : "x"; + this.scaleFactor = kwArgs.scaleFactor ? kwArgs.scaleFactor : 1.2; + this.maxScale = kwArgs.maxScale ? kwArgs.maxScale : 100; + this.enableScroll = kwArgs.enableScroll != undefined ? kwArgs.enableScroll : true; + this.enableDoubleClickZoom = kwArgs.enableDoubleClickZoom != undefined ? kwArgs.enableDoubleClickZoom : true; + this.enableKeyZoom = kwArgs.enableKeyZoom != undefined ? kwArgs.enableKeyZoom : true; + this.keyZoomModifier = kwArgs.keyZoomModifier ? kwArgs.keyZoomModifier : "ctrl"; + if(this.enableScroll){ + this._listeners.push({eventName: "onmousedown", methodName: "onMouseDown"}); + } + if(this.enableDoubleClickZoom){ + this._listeners.push({eventName: "ondblclick", methodName: "onDoubleClick"}); + } + if(this.enableKeyZoom){ + this._listeners.push({eventName: "keypress", methodName: "onKeyPress"}); + } + this._handles = []; + this.connect(); + }, + + _disconnectHandles: function(){ + if(has("ie")){ + this.chart.node.releaseCapture(); + } + arr.forEach(this._handles, connect.disconnect); + this._handles = []; + }, + + connect: function(){ + // summary: + // Connect this action to the chart. + this.inherited(arguments); + if(this.enableKeyZoom){ + // we want to be able to get focus to receive key events + domProp.set(this.chart.node, "tabindex", "0"); + // if one doesn't want a focus border he can do something like + // dojo.style(this.chart.node, "outline", "none"); + } + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the chart. + this.inherited(arguments); + if(this.enableKeyZoom){ + // we don't need anymore to be able to get focus to receive key events + domProp.set(this.chart.node, "tabindex", "-1"); + } + // in case we disconnect before the end of the action + this._disconnectHandles(); + }, + + onMouseDown: function(event){ + // summary: + // Called when mouse is down on the chart. + var chart = this.chart, axis = chart.getAxis(this.axis); + if(!axis.vertical){ + this._startCoord = event.pageX; + }else{ + this._startCoord = event.pageY; + } + this._startOffset = axis.getWindowOffset(); + this._isPanning = true; + // we now want to capture mouse move events everywhere to avoid + // stop scrolling when going out of the chart window + if(has("ie")){ + this._handles.push(connect.connect(this.chart.node, "onmousemove", this, "onMouseMove")); + this._handles.push(connect.connect(this.chart.node, "onmouseup", this, "onMouseUp")); + this.chart.node.setCapture(); + }else{ + this._handles.push(connect.connect(win.doc, "onmousemove", this, "onMouseMove")); + this._handles.push(connect.connect(win.doc, "onmouseup", this, "onMouseUp")); + } + chart.node.focus(); + // prevent the browser from trying the drag on the "image" + eventUtil.stop(event); + }, + + onMouseMove: function(event){ + // summary: + // Called when mouse is moved on the chart. + if(this._isPanning){ + var chart = this.chart, axis = chart.getAxis(this.axis); + var delta = axis.vertical?(this._startCoord- event.pageY):(event.pageX - this._startCoord); + + var bounds = axis.getScaler().bounds, + s = bounds.span / (bounds.upper - bounds.lower); + + var scale = axis.getWindowScale(); + + chart.setAxisWindow(this.axis, scale, this._startOffset - delta / s / scale); + chart.render(); + } + }, + + onMouseUp: function(event){ + // summary: + // Called when mouse is up on the chart. + this._isPanning = false; + this._disconnectHandles(); + }, + + onMouseWheel: function(event){ + // summary: + // Called when mouse wheel is used on the chart. + var scroll = event[(has("mozilla") ? "detail" : "wheelDelta")] / sUnit; + // on Mozilla the sUnit might actually not always be 3 + // make sure we never have -1 < scroll < 1 + if(scroll > -1 && scroll < 0){ + scroll = -1; + }else if(scroll > 0 && scroll < 1){ + scroll = 1; + } + this._onZoom(scroll, event); + }, + + onKeyPress: function(event){ + // summary: + // Called when a key is pressed on the chart. + if(keyTests[this.keyZoomModifier](event)){ + if(event.keyChar == "+" || event.keyCode == keys.NUMPAD_PLUS){ + this._onZoom(1, event); + }else if(event.keyChar == "-" || event.keyCode == keys.NUMPAD_MINUS){ + this._onZoom(-1, event); + } + } + }, + + onDoubleClick: function(event){ + // summary: + // Called when the mouse is double is double clicked on the chart. Toggle between zoom and fit chart. + var chart = this.chart, axis = chart.getAxis(this.axis); + var scale = 1 / this.scaleFactor; + // are we fit? + if(axis.getWindowScale()==1){ + // fit => zoom + var scaler = axis.getScaler(), start = scaler.bounds.from, end = scaler.bounds.to, + oldMiddle = (start + end) / 2, newMiddle = this.plot.toData({x: event.pageX, y: event.pageY})[this.axis], + newStart = scale * (start - oldMiddle) + newMiddle, newEnd = scale * (end - oldMiddle) + newMiddle; + chart.zoomIn(this.axis, [newStart, newEnd]); + }else{ + // non fit => fit + chart.setAxisWindow(this.axis, 1, 0); + chart.render(); + } + eventUtil.stop(event); + }, + + _onZoom: function(scroll, event){ + var scale = (scroll < 0 ? Math.abs(scroll)*this.scaleFactor : + 1 / (Math.abs(scroll)*this.scaleFactor)); + var chart = this.chart, axis = chart.getAxis(this.axis); + // after wheel reset event position exactly if we could start a new scroll action + var cscale = axis.getWindowScale(); + if(cscale / scale > this.maxScale){ + return; + } + var scaler = axis.getScaler(), start = scaler.bounds.from, end = scaler.bounds.to; + // keep mouse pointer as transformation center if available otherwise center + var middle = (event.type == "keypress") ? (start + end) / 2 : + this.plot.toData({x: event.pageX, y: event.pageY})[this.axis]; + var newStart = scale * (start - middle) + middle, newEnd = scale * (end - middle) + middle; + chart.zoomIn(this.axis, [newStart, newEnd]); + // do not scroll browser + eventUtil.stop(event); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/MoveSlice.js b/js/dojo-1.7.2/dojox/charting/action2d/MoveSlice.js new file mode 100644 index 0000000..9029120 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/MoveSlice.js @@ -0,0 +1,122 @@ +//>>built +define("dojox/charting/action2d/MoveSlice", ["dojo/_base/connect", "dojo/_base/declare", "./PlotAction", "dojo/fx/easing", "dojox/gfx/matrix", + "dojox/gfx/fx", "dojox/lang/functional", "dojox/lang/functional/scan", "dojox/lang/functional/fold"], + function(hub, declare, PlotAction, dfe, m, gf, df, dfs, dff){ + + /*===== + dojo.declare("dojox.charting.action2d.__MoveSliceCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // scale: Number? + // The amount to scale the pie slice. Default is 1.05. + scale: 1.05, + + // shift: Number? + // The amount in pixels to shift the pie slice. Default is 7. + shift: 7 + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SCALE = 1.05, + DEFAULT_SHIFT = 7; // px + + return declare("dojox.charting.action2d.MoveSlice", PlotAction, { + // summary: + // Create an action for a pie chart that moves and scales a pie slice. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut, // easing for the action + scale: DEFAULT_SCALE, // scale of magnification + shift: DEFAULT_SHIFT // shift of the slice + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the slice moving action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__MoveSliceCtorArgs? + // Optional keyword arguments object for setting parameters. + if(!kwArgs){ kwArgs = {}; } + this.scale = typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE; + this.shift = typeof kwArgs.shift == "number" ? kwArgs.shift : DEFAULT_SHIFT; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the slice moving action. + if(!o.shape || o.element != "slice" || !(o.type in this.overOutEvents)){ return; } + + if(!this.angles){ + // calculate the running total of slice angles + var startAngle = m._degToRad(o.plot.opt.startAngle); + if(typeof o.run.data[0] == "number"){ + this.angles = df.map(df.scanl(o.run.data, "+", startAngle), + "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0)); + }else{ + this.angles = df.map(df.scanl(o.run.data, "a + b.y", startAngle), + "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0)); + } + } + + var index = o.index, anim, startScale, endScale, startOffset, endOffset, + angle = (this.angles[index] + this.angles[index + 1]) / 2, + rotateTo0 = m.rotateAt(-angle, o.cx, o.cy), + rotateBack = m.rotateAt( angle, o.cx, o.cy); + + anim = this.anim[index]; + + if(anim){ + anim.action.stop(true); + }else{ + this.anim[index] = anim = {}; + } + + if(o.type == "onmouseover"){ + startOffset = 0; + endOffset = this.shift; + startScale = 1; + endScale = this.scale; + }else{ + startOffset = this.shift; + endOffset = 0; + startScale = this.scale; + endScale = 1; + } + + anim.action = gf.animateTransform({ + shape: o.shape, + duration: this.duration, + easing: this.easing, + transform: [ + rotateBack, + {name: "translate", start: [startOffset, 0], end: [endOffset, 0]}, + {name: "scaleAt", start: [startScale, o.cx, o.cy], end: [endScale, o.cx, o.cy]}, + rotateTo0 + ] + }); + + if(o.type == "onmouseout"){ + hub.connect(anim.action, "onEnd", this, function(){ + delete this.anim[index]; + }); + } + anim.action.play(); + }, + + reset: function(){ + delete this.angles; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/PlotAction.js b/js/dojo-1.7.2/dojox/charting/action2d/PlotAction.js new file mode 100644 index 0000000..2766651 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/PlotAction.js @@ -0,0 +1,79 @@ +//>>built +define("dojox/charting/action2d/PlotAction", ["dojo/_base/connect", "dojo/_base/declare", "./Base", "dojo/fx/easing", "dojox/lang/functional", + "dojox/lang/functional/object"], + function(hub, declare, Base, dfe, df, dlfo){ + + /*===== + dojox.charting.action2d.__PlotActionCtorArgs = function(duration, easing){ + // summary: + // The base keyword arguments object for creating an action2d. + // duration: Number? + // The amount of time in milliseconds for an animation to last. Default is 400. + // easing: dojo.fx.easing.*? + // An easing object (see dojo.fx.easing) for use in an animation. The + // default is dojo.fx.easing.backOut. + this.duration = duration; + this.easing = easing; + } + var Base = dojox.charting.action2d.Base; + =====*/ + + var DEFAULT_DURATION = 400, // ms + DEFAULT_EASING = dfe.backOut; + + return declare("dojox.charting.action2d.PlotAction", Base, { + // summary: + // Base action class for plot actions. + + overOutEvents: {onmouseover: 1, onmouseout: 1}, + + constructor: function(chart, plot, kwargs){ + // summary: + // Create a new base PlotAction. + // chart: dojox.charting.Chart + // The chart this action applies to. + // plot: String? + // The name of the plot this action belongs to. If none is passed "default" is assumed. + // kwargs: dojox.charting.action2d.__PlotActionCtorArgs? + // Optional arguments for the action. + this.anim = {}; + + // process common optional named parameters + if(!kwargs){ kwargs = {}; } + this.duration = kwargs.duration ? kwargs.duration : DEFAULT_DURATION; + this.easing = kwargs.easing ? kwargs.easing : DEFAULT_EASING; + }, + + connect: function(){ + // summary: + // Connect this action to the given plot. + this.handle = this.chart.connectToPlot(this.plot.name, this, "process"); + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the given plot, if connected. + if(this.handle){ + hub.disconnect(this.handle); + this.handle = null; + } + }, + + reset: function(){ + // summary: + // Reset the action. + }, + + destroy: function(){ + // summary: + // Do any cleanup needed when destroying parent elements. + this.inherited(arguments); + df.forIn(this.anim, function(o){ + df.forIn(o, function(anim){ + anim.action.stop(true); + }); + }); + this.anim = {}; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/Shake.js b/js/dojo-1.7.2/dojox/charting/action2d/Shake.js new file mode 100644 index 0000000..478e1bb --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/Shake.js @@ -0,0 +1,109 @@ +//>>built +define("dojox/charting/action2d/Shake", ["dojo/_base/connect", "dojo/_base/declare", "./PlotAction", + "dojo/fx", "dojo/fx/easing", "dojox/gfx/matrix", "dojox/gfx/fx"], + function(hub, declare, PlotAction, df, dfe, m, gf){ + + /*===== + dojo.declare("dojox.charting.action2d.__ShakeCtorArgs", dojox.charting.action2d.__PlotActionCtorArgstorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // shift: Number? + // The amount in pixels to shift the pie slice. Default is 3. + shift: 3 + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SHIFT = 3; + + return declare("dojox.charting.action2d.Shake", PlotAction, { + // summary: + // Create a shaking action for use on an element in a chart. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut, // easing for the action + shiftX: DEFAULT_SHIFT, // shift of the element along the X axis + shiftY: DEFAULT_SHIFT // shift of the element along the Y axis + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the shaking action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__ShakeCtorArgs? + // Optional keyword arguments object for setting parameters. + if(!kwArgs){ kwArgs = {}; } + this.shiftX = typeof kwArgs.shiftX == "number" ? kwArgs.shiftX : DEFAULT_SHIFT; + this.shiftY = typeof kwArgs.shiftY == "number" ? kwArgs.shiftY : DEFAULT_SHIFT; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the slice moving action. + if(!o.shape || !(o.type in this.overOutEvents)){ return; } + + var runName = o.run.name, index = o.index, vector = [], anim, + shiftX = o.type == "onmouseover" ? this.shiftX : -this.shiftX, + shiftY = o.type == "onmouseover" ? this.shiftY : -this.shiftY; + + if(runName in this.anim){ + anim = this.anim[runName][index]; + }else{ + this.anim[runName] = {}; + } + + if(anim){ + anim.action.stop(true); + }else{ + this.anim[runName][index] = anim = {}; + } + + var kwArgs = { + shape: o.shape, + duration: this.duration, + easing: this.easing, + transform: [ + {name: "translate", start: [this.shiftX, this.shiftY], end: [0, 0]}, + m.identity + ] + }; + if(o.shape){ + vector.push(gf.animateTransform(kwArgs)); + } + if(o.oultine){ + kwArgs.shape = o.outline; + vector.push(gf.animateTransform(kwArgs)); + } + if(o.shadow){ + kwArgs.shape = o.shadow; + vector.push(gf.animateTransform(kwArgs)); + } + + if(!vector.length){ + delete this.anim[runName][index]; + return; + } + + anim.action = df.combine(vector); + if(o.type == "onmouseout"){ + hub.connect(anim.action, "onEnd", this, function(){ + if(this.anim[runName]){ + delete this.anim[runName][index]; + } + }); + } + anim.action.play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/Tooltip.js b/js/dojo-1.7.2/dojox/charting/action2d/Tooltip.js new file mode 100644 index 0000000..9acad33 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/Tooltip.js @@ -0,0 +1,167 @@ +//>>built +define("dojox/charting/action2d/Tooltip", ["dojo/_base/kernel", "dijit/Tooltip","dojo/_base/lang", "dojo/_base/html", "dojo/_base/declare", "./PlotAction", + "dojox/gfx/matrix", "dojox/lang/functional", "dojox/lang/functional/scan", "dojox/lang/functional/fold"], + function(dojo, Tooltip, lang, html, declare, PlotAction, m, df, dfs, dff){ + + /*===== + dojo.declare("dojox.charting.action2d.__TooltipCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for tooltip actions. + + // text: Function? + // The function that produces the text to be shown within a tooltip. By default this will be + // set by the plot in question, by returning the value of the element. + text: null + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_TEXT = function(o){ + var t = o.run && o.run.data && o.run.data[o.index]; + if(t && typeof t != "number" && (t.tooltip || t.text)){ + return t.tooltip || t.text; + } + if(o.element == "candlestick"){ + return '<table cellpadding="1" cellspacing="0" border="0" style="font-size:0.9em;">' + + '<tr><td>Open:</td><td align="right"><strong>' + o.data.open + '</strong></td></tr>' + + '<tr><td>High:</td><td align="right"><strong>' + o.data.high + '</strong></td></tr>' + + '<tr><td>Low:</td><td align="right"><strong>' + o.data.low + '</strong></td></tr>' + + '<tr><td>Close:</td><td align="right"><strong>' + o.data.close + '</strong></td></tr>' + + (o.data.mid !== undefined ? '<tr><td>Mid:</td><td align="right"><strong>' + o.data.mid + '</strong></td></tr>' : '') + + '</table>'; + } + return o.element == "bar" ? o.x : o.y; + }; + + var pi4 = Math.PI / 4, pi2 = Math.PI / 2; + + return declare("dojox.charting.action2d.Tooltip", PlotAction, { + // summary: + // Create an action on a plot where a tooltip is shown when hovering over an element. + + // the data description block for the widget parser + defaultParams: { + text: DEFAULT_TEXT // the function to produce a tooltip from the object + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the tooltip action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__TooltipCtorArgs? + // Optional keyword arguments object for setting parameters. + this.text = kwArgs && kwArgs.text ? kwArgs.text : DEFAULT_TEXT; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the highlighting action. + if(o.type === "onplotreset" || o.type === "onmouseout"){ + Tooltip.hide(this.aroundRect); + this.aroundRect = null; + if(o.type === "onplotreset"){ + delete this.angles; + } + return; + } + + if(!o.shape || o.type !== "onmouseover"){ return; } + + // calculate relative coordinates and the position + var aroundRect = {type: "rect"}, position = ["after", "before"]; + switch(o.element){ + case "marker": + aroundRect.x = o.cx; + aroundRect.y = o.cy; + aroundRect.w = aroundRect.h = 1; + break; + case "circle": + aroundRect.x = o.cx - o.cr; + aroundRect.y = o.cy - o.cr; + aroundRect.w = aroundRect.h = 2 * o.cr; + break; + case "column": + position = ["above", "below"]; + // intentional fall down + case "bar": + aroundRect = lang.clone(o.shape.getShape()); + aroundRect.w = aroundRect.width; + aroundRect.h = aroundRect.height; + break; + case "candlestick": + aroundRect.x = o.x; + aroundRect.y = o.y; + aroundRect.w = o.width; + aroundRect.h = o.height; + break; + default: + //case "slice": + if(!this.angles){ + // calculate the running total of slice angles + if(typeof o.run.data[0] == "number"){ + this.angles = df.map(df.scanl(o.run.data, "+", 0), + "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0)); + }else{ + this.angles = df.map(df.scanl(o.run.data, "a + b.y", 0), + "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0)); + } + } + var startAngle = m._degToRad(o.plot.opt.startAngle), + angle = (this.angles[o.index] + this.angles[o.index + 1]) / 2 + startAngle; + aroundRect.x = o.cx + o.cr * Math.cos(angle); + aroundRect.y = o.cy + o.cr * Math.sin(angle); + aroundRect.w = aroundRect.h = 1; + // calculate the position + if(angle < pi4){ + // do nothing: the position is right + }else if(angle < pi2 + pi4){ + position = ["below", "above"]; + }else if(angle < Math.PI + pi4){ + position = ["before", "after"]; + }else if(angle < 2 * Math.PI - pi4){ + position = ["above", "below"]; + } + /* + else{ + // do nothing: the position is right + } + */ + break; + } + + // adjust relative coordinates to absolute, and remove fractions + var lt = this.chart.getCoords(); + aroundRect.x += lt.x; + aroundRect.y += lt.y; + aroundRect.x = Math.round(aroundRect.x); + aroundRect.y = Math.round(aroundRect.y); + aroundRect.w = Math.ceil(aroundRect.w); + aroundRect.h = Math.ceil(aroundRect.h); + this.aroundRect = aroundRect; + + var tooltip = this.text(o); + if(this.chart.getTextDir){ + var isChartDirectionRtl = (html.style(this.chart.node,"direction") == "rtl"); + var isBaseTextDirRtl = (this.chart.getTextDir(tooltip) == "rtl"); + } + if(tooltip){ + if(isBaseTextDirRtl && !isChartDirectionRtl){ + Tooltip.show("<span dir = 'rtl'>" + tooltip +"</span>", this.aroundRect, position); + } + else if(!isBaseTextDirRtl && isChartDirectionRtl){ + Tooltip.show("<span dir = 'ltr'>" + tooltip +"</span>", this.aroundRect, position); + }else{ + Tooltip.show(tooltip, this.aroundRect, position); + } + } + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/TouchIndicator.js b/js/dojo-1.7.2/dojox/charting/action2d/TouchIndicator.js new file mode 100644 index 0000000..36cec47 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/TouchIndicator.js @@ -0,0 +1,233 @@ +//>>built +define("dojox/charting/action2d/TouchIndicator", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/event", "./ChartAction", "./_IndicatorElement", "dojox/lang/utils"], + function(lang, declare, eventUtil, ChartAction, IndicatorElement, du){ + + /*===== + dojo.declare("dojox.charting.action2d.__TouchIndicatorCtorArgs", null, { + // summary: + // Additional arguments for Touch indicator. + + // series: String + // Target series name for this chart action. + series: "", + + // dualIndicator: Boolean? + // Whether a double touch on the chart creates a dual indicator showing data trend between the two touch points. Default is false. + dualIndicator: false, + + // autoScroll: Boolean? + // Whether when moving indicator the chart is automatically scrolled. Default is true. + autoScroll: true, + + // vertical: Boolean? + // Whether the indicator is vertical or not. Default is true. + vertical: true, + + // fixed: Boolean? + // Whether a fixed precision must be applied to data values for display. Default is true. + fixed: true, + + // precision: Number? + // The precision at which to round data values for display. Default is 1. + precision: 0, + + // lineStroke: gfx.Stroke? + // An optional stroke to use for indicator line. + lineStroke: {}, + + // lineOutline: dojo.gfx.Stroke? + // An optional outline to use for indicator line. + lineOutline: {}, + + // lineShadow: dojo.gfx.Stroke? + // An optional shadow to use for indicator line. + lineShadow: {}, + + // stroke: dojo.gfx.Stroke? + // An optional stroke to use for indicator label background. + stroke: {}, + + // outline: dojo.gfx.Stroke? + // An optional outline to use for indicator label background. + outline: {}, + + // shadow: dojo.gfx.Stroke? + // An optional shadow to use for indicator label background. + shadow: {}, + + // fill: dojo.gfx.Fill? + // An optional fill to use for indicator label background. + fill: {}, + + // fillFunc: Function? + // An optional function to use to compute label background fill. It takes precedence over + // fill property when available. + fillFunc: null, + + // labelFunc: Function? + // An optional function to use to compute label text. It takes precedence over + // the default text when available. + labelFunc: {}, + + // font: String? + // A font definition to use for indicator label background. + font: "", + + // fontColor: String|dojo.Color? + // The color to use for indicator label background. + fontColor: "", + + // markerStroke: dojo.gfx.Stroke? + // An optional stroke to use for indicator marker. + markerStroke: {}, + + // markerOutline: dojo.gfx.Stroke? + // An optional outline to use for indicator marker. + markerOutline: {}, + + // markerShadow: dojo.gfx.Stroke? + // An optional shadow to use for indicator marker. + markerShadow: {}, + + // markerFill: dojo.gfx.Fill? + // An optional fill to use for indicator marker. + markerFill: {}, + + // markerSymbol: String? + // An optional symbol string to use for indicator marker. + markerFill: {} + }); + var ChartAction = dojox.charting.action2d.ChartAction; + =====*/ + + return declare("dojox.charting.action2d.TouchIndicator", ChartAction, { + // summary: + // Create a touch indicator action. You can touch over the chart to display a data indicator. + + // the data description block for the widget parser + defaultParams: { + series: "", + dualIndicator: false, + vertical: true, + autoScroll: true, + fixed: true, + precision: 0 + }, + optionalParams: { + lineStroke: {}, + outlineStroke: {}, + shadowStroke: {}, + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + fillFunc: null, + labelFunc: null, + font: "", + fontColor: "", + markerStroke: {}, + markerOutline: {}, + markerShadow: {}, + markerFill: {}, + markerSymbol: "" + }, + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create a new touch indicator action and connect it. + // chart: dojox.charting.Chart + // The chart this action applies to. + // kwArgs: dojox.charting.action2d.__TouchIndicatorCtorArgs? + // Optional arguments for the chart action. + this._listeners = [{eventName: "ontouchstart", methodName: "onTouchStart"}, + {eventName: "ontouchmove", methodName: "onTouchMove"}, + {eventName: "ontouchend", methodName: "onTouchEnd"}, + {eventName: "ontouchcancel", methodName: "onTouchEnd"}]; + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this._uName = "touchIndicator"+this.opt.series; + this.connect(); + }, + + connect: function(){ + // summary: + // Connect this action to the chart. This adds a indicator plot + // to the chart that's why Chart.render() must be called after connect. + this.inherited(arguments); + // add plot with unique name + this.chart.addPlot(this._uName, {type: IndicatorElement, inter: this}); + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the chart. + var plot = this.chart.getPlot(this._uName); + if(plot.pageCoord){ + // we might still have something drawn on the screen + this.onTouchEnd(); + } + this.chart.removePlot(this._uName); + this.inherited(arguments); + }, + + onTouchStart: function(event){ + // summary: + // Called when touch is started on the chart. + if(event.touches.length==1){ + this._onTouchSingle(event, true); + }else if(this.opt.dualIndicator && event.touches.length==2){ + this._onTouchDual(event); + } + }, + + onTouchMove: function(event){ + // summary: + // Called when touch is moved on the chart. + if(event.touches.length==1){ + this._onTouchSingle(event); + }else if(this.opt.dualIndicator && event.touches.length==2){ + this._onTouchDual(event); + } + }, + + _onTouchSingle: function(event, delayed){ + // sync + if(this.chart._delayedRenderHandle && !delayed){ + // we have pending rendering from a previous call, let's sync + clearTimeout(this.chart._delayedRenderHandle); + this.chart._delayedRenderHandle = null; + this.chart.render(); + } + var plot = this.chart.getPlot(this._uName); + plot.pageCoord = {x: event.touches[0].pageX, y: event.touches[0].pageY}; + plot.dirty = true; + if(delayed){ + this.chart.delayedRender(); + }else{ + this.chart.render(); + } + eventUtil.stop(event); + }, + + _onTouchDual: function(event){ + var plot = this.chart.getPlot(this._uName); + plot.pageCoord = {x: event.touches[0].pageX, y: event.touches[0].pageY}; + plot.secondCoord = {x: event.touches[1].pageX, y: event.touches[1].pageY}; + plot.dirty = true; + this.chart.render(); + eventUtil.stop(event); + }, + + onTouchEnd: function(event){ + // summary: + // Called when touch is ended or canceled on the chart. + var plot = this.chart.getPlot(this._uName); + plot.stopTrack(); + plot.pageCoord = null; + plot.secondCoord = null; + plot.dirty = true; + this.chart.delayedRender(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/TouchZoomAndPan.js b/js/dojo-1.7.2/dojox/charting/action2d/TouchZoomAndPan.js new file mode 100644 index 0000000..9ad36b9 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/TouchZoomAndPan.js @@ -0,0 +1,250 @@ +//>>built +define("dojox/charting/action2d/TouchZoomAndPan", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/event", "dojo/_base/sniff", + "./ChartAction", "../Element", "dojox/gesture/tap", "../plot2d/common"], + function(lang, declare, eventUtil, has, ChartAction, Element, tap, common){ + var GlassView = declare("dojox.charting.action2d._GlassView", [Element], { + // summary: Private internal class used by TouchZoomAndPan actions. + // tags: + // private + constructor: function(chart){ + }, + render: function(){ + if(!this.isDirty()){ + return; + } + this.cleanGroup(); + this.group.createRect({width: this.chart.dim.width, height: this.chart.dim.height}).setFill("rgba(0,0,0,0)"); + }, + cleanGroup: function(creator){ + // summary: + // Clean any elements (HTML or GFX-based) out of our group, and create a new one. + // creator: dojox.gfx.Surface? + // An optional surface to work with. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + this.inherited(arguments); + return this; // dojox.charting.Element + }, + clear: function(){ + // summary: + // Clear out any parameters set on this plot. + // returns: dojox.charting.action2d._IndicatorElement + // The reference to this plot for functional chaining. + this.dirty = true; + // glass view needs to be above + if(this.chart.stack[0] != this){ + this.chart.movePlotToFront(this.name); + } + return this; // dojox.charting.plot2d._IndicatorElement + }, + getSeriesStats: function(){ + // summary: + // Returns default stats (irrelevant for this type of plot). + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return lang.delegate(common.defaultStats); + }, + initializeScalers: function(){ + // summary: + // Does nothing (irrelevant for this type of plot). + return this; + }, + isDirty: function(){ + // summary: + // Return whether or not this plot needs to be redrawn. + // returns: Boolean + // If this plot needs to be rendered, this will return true. + return this.dirty; + } + }); + + /*===== + + declare("dojox.charting.action2d.__TouchZoomAndPanCtorArgs", null, { + // summary: + // Additional arguments for mouse zoom and pan actions. + + // axis: String? + // Target axis name for this action. Default is "x". + axis: "x", + // scaleFactor: Number? + // The scale factor applied on double tap. Default is 1.2. + scaleFactor: 1.2, + // maxScale: Number? + // The max scale factor accepted by this action. Default is 100. + maxScale: 100, + // enableScroll: Boolean? + // Whether touch drag gesture should scroll the chart. Default is true. + enableScroll: true, + // enableZoom: Boolean? + // Whether touch pinch and spread gesture should zoom out or in the chart. Default is true. + enableZoom: true, + }); + var ChartAction = dojox.charting.action2d.ChartAction; + =====*/ + + return declare("dojox.charting.action2d.TouchZoomAndPan", ChartAction, { + // summary: + // Create a touch zoom and pan action. + // You can zoom out or in the data window with pinch and spread gestures. You can scroll using drag gesture. + // Finally this is possible to navigate between a fit window and a zoom one using double tap gesture. + + // the data description block for the widget parser + defaultParams: { + axis: "x", + scaleFactor: 1.2, + maxScale: 100, + enableScroll: true, + enableZoom: true + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create a new touch zoom and pan action and connect it. + // chart: dojox.charting.Chart + // The chart this action applies to. + // kwArgs: dojox.charting.action2d.__TouchZoomAndPanCtorArgs? + // Optional arguments for the action. + this._listeners = [{eventName: "ontouchstart", methodName: "onTouchStart"}, + {eventName: "ontouchmove", methodName: "onTouchMove"}, + {eventName: "ontouchend", methodName: "onTouchEnd"}, + {eventName: tap.doubletap, methodName: "onDoubleTap"}]; + if(!kwArgs){ kwArgs = {}; } + this.axis = kwArgs.axis ? kwArgs.axis : "x"; + this.scaleFactor = kwArgs.scaleFactor ? kwArgs.scaleFactor : 1.2; + this.maxScale = kwArgs.maxScale ? kwArgs.maxScale : 100; + this.enableScroll = kwArgs.enableScroll != undefined ? kwArgs.enableScroll : true; + this.enableZoom = kwArgs.enableScroll != undefined ? kwArgs.enableZoom : true; + this._uName = "touchZoomPan"+this.axis; + this.connect(); + }, + + connect: function(){ + // summary: + // Connect this action to the chart. On Safari this adds a new glass view plot + // to the chart that's why Chart.render() must be called after connect. + this.inherited(arguments); + // this is needed to workaround issue on Safari + SVG, because a touch start action + // started above a item that is removed during the touch action will stop + // dispatching touch events! + if(has("safari") && this.chart.surface.declaredClass.indexOf("svg")!=-1){ + this.chart.addPlot(this._uName, {type: GlassView}); + } + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the chart. + if(has("safari") && this.chart.surface.declaredClass.indexOf("svg")!=-1){ + this.chart.removePlot(this._uName); + } + this.inherited(arguments); + }, + + onTouchStart: function(event){ + // summary: + // Called when touch is started on the chart. + // we always want to be above regular plots and not clipped + var chart = this.chart, axis = chart.getAxis(this.axis); + var length = event.touches.length; + this._startPageCoord = {x: event.touches[0].pageX, y: event.touches[0].pageY}; + if((this.enableZoom || this.enableScroll) && chart._delayedRenderHandle){ + // we have pending rendering from a scroll, let's sync + clearTimeout(chart._delayedRenderHandle); + chart._delayedRenderHandle = null; + chart.render(); + } + if(this.enableZoom && length >= 2){ + this._endPageCoord = {x: event.touches[1].pageX, y: event.touches[1].pageY}; + var middlePageCoord = {x: (this._startPageCoord.x + this._endPageCoord.x) / 2, + y: (this._startPageCoord.y + this._endPageCoord.y) / 2}; + var scaler = axis.getScaler(); + this._initScale = axis.getWindowScale(); + var t = this._initData = this.plot.toData(); + this._middleCoord = t(middlePageCoord)[this.axis]; + this._startCoord = scaler.bounds.from; + this._endCoord = scaler.bounds.to; + }else if(this.enableScroll){ + this._startScroll(axis); + // needed for Android, otherwise will get a touch cancel while swiping + eventUtil.stop(event); + } + }, + + onTouchMove: function(event){ + // summary: + // Called when touch is moved on the chart. + var chart = this.chart, axis = chart.getAxis(this.axis); + var length = event.touches.length; + var pAttr = axis.vertical?"pageY":"pageX", + attr = axis.vertical?"y":"x"; + if(this.enableZoom && length >= 2){ + var newMiddlePageCoord = {x: (event.touches[1].pageX + event.touches[0].pageX) / 2, + y: (event.touches[1].pageY + event.touches[0].pageY) / 2}; + var scale = (this._endPageCoord[attr] - this._startPageCoord[attr]) / + (event.touches[1][pAttr] - event.touches[0][pAttr]); + + if(this._initScale / scale > this.maxScale){ + return; + } + + var newMiddleCoord = this._initData(newMiddlePageCoord)[this.axis]; + + var newStart = scale * (this._startCoord - newMiddleCoord) + this._middleCoord, + newEnd = scale * (this._endCoord - newMiddleCoord) + this._middleCoord; + chart.zoomIn(this.axis, [newStart, newEnd]); + // avoid browser pan + eventUtil.stop(event); + }else if(this.enableScroll){ + var delta = axis.vertical?(this._startPageCoord[attr] - event.touches[0][pAttr]): + (event.touches[0][pAttr] - this._startPageCoord[attr]); + chart.setAxisWindow(this.axis, this._lastScale, this._initOffset - delta / this._lastFactor / this._lastScale); + chart.delayedRender(); + // avoid browser pan + eventUtil.stop(event); + } + }, + + onTouchEnd: function(event){ + // summary: + // Called when touch is ended on the chart. + var chart = this.chart, axis = chart.getAxis(this.axis); + if(event.touches.length == 1 && this.enableScroll){ + // still one touch available, let's start back from here for + // potential pan + this._startPageCoord = {x: event.touches[0].pageX, y: event.touches[0].pageY}; + this._startScroll(axis); + } + }, + + _startScroll: function(axis){ + var bounds = axis.getScaler().bounds; + this._initOffset = axis.getWindowOffset(); + // we keep it because of delay rendering we might now always have access to the + // information to compute it + this._lastScale = axis.getWindowScale(); + this._lastFactor = bounds.span / (bounds.upper - bounds.lower); + }, + + onDoubleTap: function(event){ + // summary: + // Called when double tap is performed on the chart. + var chart = this.chart, axis = chart.getAxis(this.axis); + var scale = 1 / this.scaleFactor; + // are we fit? + if(axis.getWindowScale()==1){ + // fit => zoom + var scaler = axis.getScaler(), start = scaler.bounds.from, end = scaler.bounds.to, + oldMiddle = (start + end) / 2, newMiddle = this.plot.toData(this._startPageCoord)[this.axis], + newStart = scale * (start - oldMiddle) + newMiddle, newEnd = scale * (end - oldMiddle) + newMiddle; + chart.zoomIn(this.axis, [newStart, newEnd]); + }else{ + // non fit => fit + chart.setAxisWindow(this.axis, 1, 0); + chart.render(); + } + eventUtil.stop(event); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/action2d/_IndicatorElement.js b/js/dojo-1.7.2/dojox/charting/action2d/_IndicatorElement.js new file mode 100644 index 0000000..ab71c63 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/action2d/_IndicatorElement.js @@ -0,0 +1,371 @@ +//>>built +define("dojox/charting/action2d/_IndicatorElement", ["dojo/_base/lang", "dojo/_base/declare", "../Element", "../plot2d/common", + "../axis2d/common", "dojox/gfx"], + function(lang, declare, Element, dcpc, dcac, gfx){ + + // all the code below should be removed when http://trac.dojotoolkit.org/ticket/11299 will be available + var getBoundingBox = function(shape){ + return getTextBBox(shape, shape.getShape().text); + }; + var getTextBBox = function(s, t){ + var c = s.declaredClass; + if (c.indexOf("svg")!=-1){ + // try/catch the FF native getBBox error. cheaper than walking up in the DOM + // hierarchy to check the conditions (bench show /10 ) + try { + return lang.mixin({}, s.rawNode.getBBox()); + }catch (e){ + return null; + } + }else if(c.indexOf("vml")!=-1){ + var rawNode = s.rawNode, _display = rawNode.style.display; + rawNode.style.display = "inline"; + var w = gfx.pt2px(parseFloat(rawNode.currentStyle.width)); + var h = gfx.pt2px(parseFloat(rawNode.currentStyle.height)); + var sz = {x: 0, y: 0, width: w, height: h}; + // in VML, the width/height we get are in view coordinates + // in our case we don't zoom the view so that is ok + // It's impossible to get the x/y from the currentStyle.left/top, + // because all negative coordinates are 'clipped' to 0. + // (x:0 + translate(-100) -> x=0 + computeLocation(s, sz); + rawNode.style.display = _display; + return sz; + }else if(c.indexOf("silverlight")!=-1){ + var bb = {width: s.rawNode.actualWidth, height: s.rawNode.actualHeight}; + return computeLocation(s, bb, 0.75); + }else if(s.getTextWidth){ + // canvas + var w = s.getTextWidth(); + var font = s.getFont(); + var fz = font ? font.size : gfx.defaultFont.size; + var h = gfx.normalizedLength(fz); + sz = {width: w, height: h}; + computeLocation(s, sz, 0.75); + return sz; + } + }; + var computeLocation = function(s, sz, coef){ + var width = sz.width, height = sz.height, sh = s.getShape(), align = sh.align; + switch (align) { + case "end": + sz.x = sh.x - width; + break; + case "middle": + sz.x = sh.x - width / 2; + break; + case "start": + default: + sz.x = sh.x; + break; + } + coef = coef || 1; + sz.y = sh.y - height*coef; // rough approximation of the ascent!... + return sz; + }; + + return declare("dojox.charting.action2d._IndicatorElement",[Element], { + // summary: + // Internal element used by indicator actions. + // tags: + // private + constructor: function(chart, kwArgs){ + if(!kwArgs){ kwArgs = {}; } + this.inter = kwArgs.inter; + }, + _updateVisibility: function(cp, limit, attr){ + var axis = attr=="x"?this.inter.plot._hAxis:this.inter.plot._vAxis; + var scale = axis.getWindowScale(); + this.chart.setAxisWindow(axis.name, scale, axis.getWindowOffset() + (cp[attr] - limit[attr]) / scale); + this._noDirty = true; + this.chart.render(); + this._noDirty = false; + if(!this._tracker){ + this.initTrack(); + } + }, + _trackMove: function(){ + // let's update the selector + this._updateIndicator(this.pageCoord); + // if we reached that point once, then we don't stop until mouse up + if(this._initTrackPhase){ + this._initTrackPhase = false; + this._tracker = setInterval(lang.hitch(this, this._trackMove), 100); + } + }, + initTrack: function(){ + this._initTrackPhase = true; + this._tracker = setTimeout(lang.hitch(this, this._trackMove), 500); + }, + stopTrack: function(){ + if(this._tracker){ + if(this._initTrackPhase){ + clearTimeout(this._tracker); + }else{ + clearInterval(this._tracker); + } + this._tracker = null; + } + }, + render: function(){ + if(!this.isDirty()){ + return; + } + + this.cleanGroup(); + + if (!this.pageCoord){ + return; + } + + this._updateIndicator(this.pageCoord, this.secondCoord); + }, + _updateIndicator: function(cp1, cp2){ + var inter = this.inter, plot = inter.plot, v = inter.opt.vertical; + var hAxis = this.chart.getAxis(plot.hAxis), vAxis = this.chart.getAxis(plot.vAxis); + var hn = hAxis.name, vn = vAxis.name, hb = hAxis.getScaler().bounds, vb = vAxis.getScaler().bounds; + var attr = v?"x":"y", n = v?hn:vn, bounds = v?hb:vb; + + // sort data point + if(cp2){ + var tmp; + if(v){ + if(cp1.x>cp2.x){ + tmp = cp2; + cp2 = cp1; + cp1 = tmp; + } + }else{ + if(cp1.y>cp2.y){ + tmp = cp2; + cp2 = cp1; + cp1 = tmp; + } + } + } + + var cd1 = plot.toData(cp1), cd2; + if(cp2){ + cd2 = plot.toData(cp2); + } + + var o = {}; + o[hn] = hb.from; + o[vn] = vb.from; + var min = plot.toPage(o); + o[hn] = hb.to; + o[vn] = vb.to; + var max = plot.toPage(o); + + if(cd1[n] < bounds.from){ + // do not autoscroll if dual indicator + if(!cd2 && inter.opt.autoScroll){ + this._updateVisibility(cp1, min, attr); + return; + }else{ + cp1[attr] = min[attr]; + } + // cp1 might have changed, let's update cd1 + cd1 = plot.toData(cp1); + }else if(cd1[n] > bounds.to){ + if(!cd2 && inter.opt.autoScroll){ + this._updateVisibility(cp1, max, attr); + return; + }else{ + cp1[attr] = max[attr]; + } + // cp1 might have changed, let's update cd1 + cd1 = plot.toData(cp1); + } + + var c1 = this._getData(cd1, attr, v), c2; + + if(c1.y == null){ + // we have no data for that point let's just return + return; + } + + if(cp2){ + if(cd2[n] < bounds.from){ + cp2[attr] = min[attr]; + cd2 = plot.toData(cp2); + }else if(cd2[n] > bounds.to){ + cp2[attr] = max[attr]; + cd2 = plot.toData(cp2); + } + c2 = this._getData(cd2, attr, v); + if(c2.y == null){ + // we have no data for that point let's pretend we have a single touch point + cp2 = null; + } + } + + var t1 = this._renderIndicator(c1, cp2?1:0, hn, vn, min, max); + if(cp2){ + var t2 = this._renderIndicator(c2, 2, hn, vn, min, max); + var delta = v?c2.y-c1.y:c2.x-c1.y; + var text = inter.opt.labelFunc?inter.opt.labelFunc(c1, c2, inter.opt.fixed, inter.opt.precision): + (dcpc.getLabel(delta, inter.opt.fixed, inter.opt.precision)+" ("+dcpc.getLabel(100*delta/(v?c1.y:c1.x), true, 2)+"%)"); + this._renderText(text, inter, this.chart.theme, v?(t1.x+t2.x)/2:t1.x, v?t1.y:(t1.y+t2.y)/2, c1, c2); + }; + + }, + _renderIndicator: function(coord, index, hn, vn, min, max){ + var t = this.chart.theme, c = this.chart.getCoords(), inter = this.inter, plot = inter.plot, v = inter.opt.vertical; + + var mark = {}; + mark[hn] = coord.x; + mark[vn] = coord.y; + mark = plot.toPage(mark); + + var cx = mark.x - c.x, cy = mark.y - c.y; + var x1 = v?cx:min.x - c.x, y1 = v?min.y - c.y:cy, x2 = v?x1:max.x - c.x, y2 = v?max.y - c.y:y1; + var sh = inter.opt.lineShadow?inter.opt.lineShadow:t.indicator.lineShadow, + ls = inter.opt.lineStroke?inter.opt.lineStroke:t.indicator.lineStroke, + ol = inter.opt.lineOutline?inter.opt.lineOutline:t.indicator.lineOutline; + if(sh){ + this.group.createLine({x1: x1 + sh.dx, y1: y1 + sh.dy, x2: x2 + sh.dx, y2: y2 + sh.dy}).setStroke(sh); + } + if(ol){ + ol = dcpc.makeStroke(ol); + ol.width = 2 * ol.width + ls.width; + this.group.createLine({x1: x1, y1: y1, x2: x2, y2: y2}).setStroke(ol); + } + this.group.createLine({x1: x1, y1: y1, x2: x2, y2: y2}).setStroke(ls); + + var ms = inter.opt.markerSymbol?inter.opt.markerSymbol:t.indicator.markerSymbol, + path = "M" + cx + " " + cy + " " + ms; + sh = inter.opt.markerShadow?inter.opt.markerShadow:t.indicator.markerShadow; + ls = inter.opt.markerStroke?inter.opt.markerStroke:t.indicator.markerStroke; + ol = inter.opt.markerOutline?inter.opt.markerOutline:t.indicator.markerOutline; + if(sh){ + var sp = "M" + (cx + sh.dx) + " " + (cy + sh.dy) + " " + ms; + this.group.createPath(sp).setFill(sh.color).setStroke(sh); + } + if(ol){ + ol = dcpc.makeStroke(ol); + ol.width = 2 * ol.width + ls.width; + this.group.createPath(path).setStroke(ol); + } + + var shape = this.group.createPath(path); + var sf = this._shapeFill(inter.opt.markerFill?inter.opt.markerFill:t.indicator.markerFill, shape.getBoundingBox()); + shape.setFill(sf).setStroke(ls); + + if(index==0){ + var text = inter.opt.labelFunc?inter.opt.labelFunc(coord, null, inter.opt.fixed, inter.opt.precision): + dcpc.getLabel(v?coord.y:coord.x, inter.opt.fixed, inter.opt.precision); + this._renderText(text, inter, t, v?x1:x2+5, v?y2+5:y1, coord); + }else{ + return v?{x: x1, y: y2+5}:{x: x2+5, y: y1}; + } + + }, + _renderText: function(text, inter, t, x, y, c1, c2){ + var label = dcac.createText.gfx( + this.chart, + this.group, + x, y, + "middle", + text, inter.opt.font?inter.opt.font:t.indicator.font, inter.opt.fontColor?inter.opt.fontColor:t.indicator.fontColor); + var b = getBoundingBox(label); + b.x-=2; b.y-=1; b.width+=4; b.height+=2; b.r = inter.opt.radius?inter.opt.radius:t.indicator.radius; + sh = inter.opt.shadow?inter.opt.shadow:t.indicator.shadow; + ls = inter.opt.stroke?inter.opt.stroke:t.indicator.stroke; + ol = inter.opt.outline?inter.opt.outline:t.indicator.outline; + if(sh){ + this.group.createRect(b).setFill(sh.color).setStroke(sh); + } + if(ol){ + ol = dcpc.makeStroke(ol); + ol.width = 2 * ol.width + ls.width; + this.group.createRect(b).setStroke(ol); + } + var f = inter.opt.fillFunc?inter.opt.fillFunc(c1, c2):(inter.opt.fill?inter.opt.fill:t.indicator.fill); + this.group.createRect(b).setFill(this._shapeFill(f, b)).setStroke(ls); + label.moveToFront(); + }, + _getData: function(cd, attr, v){ + // we need to find which actual data point is "close" to the data value + var data = this.chart.getSeries(this.inter.opt.series).data; + // let's consider data are sorted because anyway rendering will be "weird" with unsorted data + // i is an index in the array, which is different from a x-axis value even for index based data + var i, r, l = data.length; + for (i = 0; i < l; ++i){ + r = data[i]; + if(r == null){ + // move to next item + }else if(typeof r == "number"){ + if(i + 1 > cd[attr]){ + break; + } + }else if(r[attr] > cd[attr]){ + break; + } + } + var x,y,px,py; + if(typeof r == "number"){ + x = i+1; + y = r; + if(i>0){ + px = i; + py = data[i-1]; + } + }else{ + x = r.x; + y = r.y; + if(i>0){ + px = data[i-1].x; + py = data[i-1].y; + } + } + if(i>0){ + var m = v?(x+px)/2:(y+py)/2; + if(cd[attr]<=m){ + x = px; + y = py; + } + } + return {x: x, y: y}; + }, + cleanGroup: function(creator){ + // summary: + // Clean any elements (HTML or GFX-based) out of our group, and create a new one. + // creator: dojox.gfx.Surface? + // An optional surface to work with. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + this.inherited(arguments); + // we always want to be above regular plots and not clipped + this.group.moveToFront(); + return this; // dojox.charting.Element + }, + clear: function(){ + // summary: + // Clear out any parameters set on this plot. + // returns: dojox.charting.action2d._IndicatorElement + // The reference to this plot for functional chaining. + this.dirty = true; + return this; // dojox.charting.plot2d._IndicatorElement + }, + getSeriesStats: function(){ + // summary: + // Returns default stats (irrelevant for this type of plot). + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return lang.delegate(dcpc.defaultStats); + }, + initializeScalers: function(){ + // summary: + // Does nothing (irrelevant for this type of plot). + return this; + }, + isDirty: function(){ + // summary: + // Return whether or not this plot needs to be redrawn. + // returns: Boolean + // If this plot needs to be rendered, this will return true. + return !this._noDirty && (this.dirty || this.inter.plot.isDirty()); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/axis2d/Base.js b/js/dojo-1.7.2/dojox/charting/axis2d/Base.js new file mode 100644 index 0000000..5c0f690 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/axis2d/Base.js @@ -0,0 +1,72 @@ +//>>built +define("dojox/charting/axis2d/Base", ["dojo/_base/declare", "../Element"], + function(declare, Element){ +/*===== +var Element = dojox.charting.Element; +=====*/ +return declare("dojox.charting.axis2d.Base", Element, { + // summary: + // The base class for any axis. This is more of an interface/API + // definition than anything else; see dojox.charting.axis2d.Default + // for more details. + constructor: function(chart, kwArgs){ + // summary: + // Return a new base axis. + // chart: dojox.charting.Chart + // The chart this axis belongs to. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // An optional arguments object to define the axis parameters. + this.vertical = kwArgs && kwArgs.vertical; + }, + clear: function(){ + // summary: + // Stub function for clearing the axis. + // returns: dojox.charting.axis2d.Base + // A reference to the axis for functional chaining. + return this; // dojox.charting.axis2d.Base + }, + initialized: function(){ + // summary: + // Return a flag as to whether or not this axis has been initialized. + // returns: Boolean + // If the axis is initialized or not. + return false; // Boolean + }, + calculate: function(min, max, span){ + // summary: + // Stub function to run the calcuations needed for drawing this axis. + // returns: dojox.charting.axis2d.Base + // A reference to the axis for functional chaining. + return this; // dojox.charting.axis2d.Base + }, + getScaler: function(){ + // summary: + // A stub function to return the scaler object created during calculate. + // returns: Object + // The scaler object (see dojox.charting.scaler.linear for more information) + return null; // Object + }, + getTicks: function(){ + // summary: + // A stub function to return the object that helps define how ticks are rendered. + // returns: Object + // The ticks object. + return null; // Object + }, + getOffsets: function(){ + // summary: + // A stub function to return any offsets needed for axis and series rendering. + // returns: Object + // An object of the form { l, r, t, b }. + return {l: 0, r: 0, t: 0, b: 0}; // Object + }, + render: function(dim, offsets){ + // summary: + // Stub function to render this axis. + // returns: dojox.charting.axis2d.Base + // A reference to the axis for functional chaining. + this.dirty = false; + return this; // dojox.charting.axis2d.Base + } +}); +}); diff --git a/js/dojo-1.7.2/dojox/charting/axis2d/Default.js b/js/dojo-1.7.2/dojox/charting/axis2d/Default.js new file mode 100644 index 0000000..9428e9d --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/axis2d/Default.js @@ -0,0 +1,800 @@ +//>>built +define("dojox/charting/axis2d/Default", ["dojo/_base/lang", "dojo/_base/array","dojo/_base/sniff", "dojo/_base/declare", + "dojo/_base/connect", "dojo/_base/html", "dojo/dom-geometry", "./Invisible", + "../scaler/common", "../scaler/linear", "./common", "dojox/gfx", "dojox/lang/utils"], + function(lang, arr, has, declare, connect, html, domGeom, Invisible, scommon, + lin, acommon, g, du){ + + /*===== + dojox.charting.axis2d.__AxisCtorArgs = function( + vertical, fixUpper, fixLower, natural, leftBottom, + includeZero, fixed, majorLabels, minorTicks, minorLabels, microTicks, htmlLabels, + min, max, from, to, majorTickStep, minorTickStep, microTickStep, + labels, labelFunc, maxLabelSize, + stroke, majorTick, minorTick, microTick, tick, + font, fontColor + ){ + // summary: + // Optional arguments used in the definition of an axis. + // + // vertical: Boolean? + // A flag that says whether an axis is vertical (i.e. y axis) or horizontal. Default is false (horizontal). + // fixUpper: String? + // Align the greatest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none". + // fixLower: String? + // Align the smallest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none". + // natural: Boolean? + // Ensure tick marks are made on "natural" numbers. Defaults to false. + // leftBottom: Boolean? + // The position of a vertical axis; if true, will be placed against the left-bottom corner of the chart. Defaults to true. + // includeZero: Boolean? + // Include 0 on the axis rendering. Default is false. + // fixed: Boolean? + // Force all axis labels to be fixed numbers. Default is true. + // majorLabels: Boolean? + // Flag to draw all labels at major ticks. Default is true. + // minorTicks: Boolean? + // Flag to draw minor ticks on an axis. Default is true. + // minorLabels: Boolean? + // Flag to draw labels on minor ticks. Default is true. + // microTicks: Boolean? + // Flag to draw micro ticks on an axis. Default is false. + // htmlLabels: Boolean? + // Flag to use HTML (as opposed to the native vector graphics engine) to draw labels. Default is true. + // min: Number? + // The smallest value on an axis. Default is 0. + // max: Number? + // The largest value on an axis. Default is 1. + // from: Number? + // Force the chart to render data visible from this value. Default is 0. + // to: Number? + // Force the chart to render data visible to this value. Default is 1. + // majorTickStep: Number? + // The amount to skip before a major tick is drawn. Default is 4. + // minorTickStep: Number? + // The amount to skip before a minor tick is drawn. Default is 2. + // microTickStep: Number? + // The amount to skip before a micro tick is drawn. Default is 1. + // labels: Object[]? + // An array of labels for major ticks, with corresponding numeric values, ordered by value. + // labelFunc: Function? + // An optional function used to compute label values. + // maxLabelSize: Number? + // The maximum size, in pixels, for a label. To be used with the optional label function. + // stroke: dojox.gfx.Stroke? + // An optional stroke to be used for drawing an axis. + // majorTick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a major tick. + // minorTick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a minor tick. + // microTick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a micro tick. + // tick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a tick. + // font: String? + // An optional font definition (as used in the CSS font property) for labels. + // fontColor: String|dojo.Color? + // An optional color to be used in drawing labels. + // enableCache: Boolean? + // Whether the ticks and labels are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. For labels it is only working with gfx labels + // not html ones. Default false. + + this.vertical = vertical; + this.fixUpper = fixUpper; + this.fixLower = fixLower; + this.natural = natural; + this.leftBottom = leftBottom; + this.includeZero = includeZero; + this.fixed = fixed; + this.majorLabels = majorLabels; + this.minorTicks = minorTicks; + this.minorLabels = minorLabels; + this.microTicks = microTicks; + this.htmlLabels = htmlLabels; + this.min = min; + this.max = max; + this.from = from; + this.to = to; + this.majorTickStep = majorTickStep; + this.minorTickStep = minorTickStep; + this.microTickStep = microTickStep; + this.labels = labels; + this.labelFunc = labelFunc; + this.maxLabelSize = maxLabelSize; + this.stroke = stroke; + this.majorTick = majorTick; + this.minorTick = minorTick; + this.microTick = microTick; + this.tick = tick; + this.font = font; + this.fontColor = fontColor; + this.enableCache = enableCache; + } + var Invisible = dojox.charting.axis2d.Invisible + =====*/ + + var labelGap = 4, // in pixels + centerAnchorLimit = 45; // in degrees + + return declare("dojox.charting.axis2d.Default", Invisible, { + // summary: + // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details. + // + // defaultParams: Object + // The default parameters used to define any axis. + // optionalParams: Object + // Any optional parameters needed to define an axis. + + /* + // TODO: the documentation tools need these to be pre-defined in order to pick them up + // correctly, but the code here is partially predicated on whether or not the properties + // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT + + // opt: Object + // The actual options used to define this axis, created at initialization. + // scalar: Object + // The calculated helper object to tell charts how to draw an axis and any data. + // ticks: Object + // The calculated tick object that helps a chart draw the scaling on an axis. + // dirty: Boolean + // The state of the axis (whether it needs to be redrawn or not) + // scale: Number + // The current scale of the axis. + // offset: Number + // The current offset of the axis. + + opt: null, + scalar: null, + ticks: null, + dirty: true, + scale: 1, + offset: 0, + */ + defaultParams: { + vertical: false, // true for vertical axis + fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none" + fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none" + natural: false, // all tick marks should be made on natural numbers + leftBottom: true, // position of the axis, used with "vertical" + includeZero: false, // 0 should be included + fixed: true, // all labels are fixed numbers + majorLabels: true, // draw major labels + minorTicks: true, // draw minor ticks + minorLabels: true, // draw minor labels + microTicks: false, // draw micro ticks + rotation: 0, // label rotation angle in degrees + htmlLabels: true, // use HTML to draw labels + enableCache: false // whether we cache or not + }, + optionalParams: { + min: 0, // minimal value on this axis + max: 1, // maximal value on this axis + from: 0, // visible from this value + to: 1, // visible to this value + majorTickStep: 4, // major tick step + minorTickStep: 2, // minor tick step + microTickStep: 1, // micro tick step + labels: [], // array of labels for major ticks + // with corresponding numeric values + // ordered by values + labelFunc: null, // function to compute label values + maxLabelSize: 0, // size in px. For use with labelFunc + maxLabelCharCount: 0, // size in word count. + trailingSymbol: null, + + // TODO: add support for minRange! + // minRange: 1, // smallest distance from min allowed on the axis + + // theme components + stroke: {}, // stroke for an axis + majorTick: {}, // stroke + length for a tick + minorTick: {}, // stroke + length for a tick + microTick: {}, // stroke + length for a tick + tick: {}, // stroke + length for a tick + font: "", // font for labels + fontColor: "", // color for labels as a string + title: "", // axis title + titleGap: 0, // gap between axis title and axis label + titleFont: "", // axis title font + titleFontColor: "", // axis title font color + titleOrientation: "" // "axis" means the title facing the axis, "away" means facing away + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for an axis. + // chart: dojox.charting.Chart + // The chart the axis belongs to. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // Any optional keyword arguments to be used to define this axis. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + if(this.opt.enableCache){ + this._textFreePool = []; + this._lineFreePool = []; + this._textUsePool = []; + this._lineUsePool = []; + } + }, + getOffsets: function(){ + // summary: + // Get the physical offset values for this axis (used in drawing data series). + // returns: Object + // The calculated offsets in the form of { l, r, t, b } (left, right, top, bottom). + var s = this.scaler, offsets = { l: 0, r: 0, t: 0, b: 0 }; + if(!s){ + return offsets; + } + var o = this.opt, labelWidth = 0, a, b, c, d, + gl = scommon.getNumericLabel, + offset = 0, ma = s.major, mi = s.minor, + ta = this.chart.theme.axis, + // TODO: we use one font --- of major tick, we need to use major and minor fonts + taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), + taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont), + taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15, + taMajorTick = this.chart.theme.getTick("major", o), + taMinorTick = this.chart.theme.getTick("minor", o), + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0, + rotation = o.rotation % 360, leftBottom = o.leftBottom, + cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), + sinr = Math.abs(Math.sin(rotation * Math.PI / 180)); + this.trailingSymbol = (o.trailingSymbol === undefined || o.trailingSymbol === null) ? this.trailingSymbol : o.trailingSymbol; + if(rotation < 0){ + rotation += 360; + } + + if(size){ + // we need width of all labels + if(this.labels){ + labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount); + }else{ + labelWidth = this._groupLabelWidth([ + gl(ma.start, ma.prec, o), + gl(ma.start + ma.count * ma.tick, ma.prec, o), + gl(mi.start, mi.prec, o), + gl(mi.start + mi.count * mi.tick, mi.prec, o) + ], taFont, o.maxLabelCharCount); + } + labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth; + if(this.vertical){ + var side = leftBottom ? "l" : "r"; + switch(rotation){ + case 0: + case 180: + offsets[side] = labelWidth; + offsets.t = offsets.b = size / 2; + break; + case 90: + case 270: + offsets[side] = size; + offsets.t = offsets.b = labelWidth / 2; + break; + default: + if(rotation <= centerAnchorLimit || (180 < rotation && rotation <= (180 + centerAnchorLimit))){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "t" : "b"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "b" : "t"] = size * cosr / 2; + }else if(rotation > (360 - centerAnchorLimit) || (180 > rotation && rotation > (180 - centerAnchorLimit))){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "b" : "t"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "t" : "b"] = size * cosr / 2; + }else if(rotation < 90 || (180 < rotation && rotation < 270)){ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "t" : "b"] = size * cosr + labelWidth * sinr; + }else{ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "b" : "t"] = size * cosr + labelWidth * sinr; + } + break; + } + offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0); + }else{ + var side = leftBottom ? "b" : "t"; + switch(rotation){ + case 0: + case 180: + offsets[side] = size; + offsets.l = offsets.r = labelWidth / 2; + break; + case 90: + case 270: + offsets[side] = labelWidth; + offsets.l = offsets.r = size / 2; + break; + default: + if((90 - centerAnchorLimit) <= rotation && rotation <= 90 || (270 - centerAnchorLimit) <= rotation && rotation <= 270){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "r" : "l"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "l" : "r"] = size * cosr / 2; + }else if(90 <= rotation && rotation <= (90 + centerAnchorLimit) || 270 <= rotation && rotation <= (270 + centerAnchorLimit)){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "l" : "r"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "r" : "l"] = size * cosr / 2; + }else if(rotation < centerAnchorLimit || (180 < rotation && rotation < (180 - centerAnchorLimit))){ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "r" : "l"] = size * cosr + labelWidth * sinr; + }else{ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "l" : "r"] = size * cosr + labelWidth * sinr; + } + break; + } + offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0); + } + } + if(labelWidth){ + this._cachedLabelWidth = labelWidth; + } + return offsets; // Object + }, + cleanGroup: function(creator){ + if(this.opt.enableCache && this.group){ + this._lineFreePool = this._lineFreePool.concat(this._lineUsePool); + this._lineUsePool = []; + this._textFreePool = this._textFreePool.concat(this._textUsePool); + this._textUsePool = []; + } + this.inherited(arguments); + }, + createText: function(labelType, creator, x, y, align, textContent, font, fontColor, labelWidth){ + if(!this.opt.enableCache || labelType=="html"){ + return acommon.createText[labelType]( + this.chart, + creator, + x, + y, + align, + textContent, + font, + fontColor, + labelWidth + ); + } + var text; + if (this._textFreePool.length > 0){ + text = this._textFreePool.pop(); + text.setShape({x: x, y: y, text: textContent, align: align}); + // For now all items share the same font, no need to re-set it + //.setFont(font).setFill(fontColor); + // was cleared, add it back + creator.add(text); + }else{ + text = acommon.createText[labelType]( + this.chart, + creator, + x, + y, + align, + textContent, + font, + fontColor, + labelWidth + ); } + this._textUsePool.push(text); + return text; + }, + createLine: function(creator, params){ + var line; + if(this.opt.enableCache && this._lineFreePool.length > 0){ + line = this._lineFreePool.pop(); + line.setShape(params); + // was cleared, add it back + creator.add(line); + }else{ + line = creator.createLine(params); + } + if(this.opt.enableCache){ + this._lineUsePool.push(line); + } + return line; + }, + render: function(dim, offsets){ + // summary: + // Render/draw the axis. + // dim: Object + // An object of the form { width, height}. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + if(!this.dirty){ + return this; // dojox.charting.axis2d.Default + } + // prepare variable + var o = this.opt, ta = this.chart.theme.axis, leftBottom = o.leftBottom, rotation = o.rotation % 360, + start, stop, titlePos, titleRotation=0, titleOffset, axisVector, tickVector, anchorOffset, labelOffset, labelAlign, + + // TODO: we use one font --- of major tick, we need to use major and minor fonts + taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), + taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont), + // TODO: we use one font color --- we need to use different colors + taFontColor = o.fontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "black", + taTitleFontColor = o.titleFontColor || (ta.tick && ta.tick.titleFontColor) || "black", + taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15, + taTitleOrientation = o.titleOrientation || (ta.tick && ta.tick.titleOrientation) || "axis", + taMajorTick = this.chart.theme.getTick("major", o), + taMinorTick = this.chart.theme.getTick("minor", o), + taMicroTick = this.chart.theme.getTick("micro", o), + + tickSize = Math.max(taMajorTick.length, taMinorTick.length, taMicroTick.length), + taStroke = "stroke" in o ? o.stroke : ta.stroke, + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), + sinr = Math.abs(Math.sin(rotation * Math.PI / 180)), + tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0; + if(rotation < 0){ + rotation += 360; + } + if(this.vertical){ + start = {y: dim.height - offsets.b}; + stop = {y: offsets.t}; + titlePos = {y: (dim.height - offsets.b + offsets.t)/2}; + titleOffset = size * sinr + (this._cachedLabelWidth || 0) * cosr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap; + axisVector = {x: 0, y: -1}; + labelOffset = {x: 0, y: 0}; + tickVector = {x: 1, y: 0}; + anchorOffset = {x: labelGap, y: 0}; + switch(rotation){ + case 0: + labelAlign = "end"; + labelOffset.y = size * 0.4; + break; + case 90: + labelAlign = "middle"; + labelOffset.x = -size; + break; + case 180: + labelAlign = "start"; + labelOffset.y = -size * 0.4; + break; + case 270: + labelAlign = "middle"; + break; + default: + if(rotation < centerAnchorLimit){ + labelAlign = "end"; + labelOffset.y = size * 0.4; + }else if(rotation < 90){ + labelAlign = "end"; + labelOffset.y = size * 0.4; + }else if(rotation < (180 - centerAnchorLimit)){ + labelAlign = "start"; + }else if(rotation < (180 + centerAnchorLimit)){ + labelAlign = "start"; + labelOffset.y = -size * 0.4; + }else if(rotation < 270){ + labelAlign = "start"; + labelOffset.x = leftBottom ? 0 : size * 0.4; + }else if(rotation < (360 - centerAnchorLimit)){ + labelAlign = "end"; + labelOffset.x = leftBottom ? 0 : size * 0.4; + }else{ + labelAlign = "end"; + labelOffset.y = size * 0.4; + } + } + if(leftBottom){ + start.x = stop.x = offsets.l; + titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 90 : 270; + titlePos.x = offsets.l - titleOffset + (titleRotation == 270 ? tsize : 0); + tickVector.x = -1; + anchorOffset.x = -anchorOffset.x; + }else{ + start.x = stop.x = dim.width - offsets.r; + titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 90 : 270; + titlePos.x = dim.width - offsets.r + titleOffset - (titleRotation == 270 ? 0 : tsize); + switch(labelAlign){ + case "start": + labelAlign = "end"; + break; + case "end": + labelAlign = "start"; + break; + case "middle": + labelOffset.x += size; + break; + } + } + }else{ + start = {x: offsets.l}; + stop = {x: dim.width - offsets.r}; + titlePos = {x: (dim.width - offsets.r + offsets.l)/2}; + titleOffset = size * cosr + (this._cachedLabelWidth || 0) * sinr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap; + axisVector = {x: 1, y: 0}; + labelOffset = {x: 0, y: 0}; + tickVector = {x: 0, y: 1}; + anchorOffset = {x: 0, y: labelGap}; + switch(rotation){ + case 0: + labelAlign = "middle"; + labelOffset.y = size; + break; + case 90: + labelAlign = "start"; + labelOffset.x = -size * 0.4; + break; + case 180: + labelAlign = "middle"; + break; + case 270: + labelAlign = "end"; + labelOffset.x = size * 0.4; + break; + default: + if(rotation < (90 - centerAnchorLimit)){ + labelAlign = "start"; + labelOffset.y = leftBottom ? size : 0; + }else if(rotation < (90 + centerAnchorLimit)){ + labelAlign = "start"; + labelOffset.x = -size * 0.4; + }else if(rotation < 180){ + labelAlign = "start"; + labelOffset.y = leftBottom ? 0 : -size; + }else if(rotation < (270 - centerAnchorLimit)){ + labelAlign = "end"; + labelOffset.y = leftBottom ? 0 : -size; + }else if(rotation < (270 + centerAnchorLimit)){ + labelAlign = "end"; + labelOffset.y = leftBottom ? size * 0.4 : 0; + }else{ + labelAlign = "end"; + labelOffset.y = leftBottom ? size : 0; + } + } + if(leftBottom){ + start.y = stop.y = dim.height - offsets.b; + titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 180 : 0; + titlePos.y = dim.height - offsets.b + titleOffset - (titleRotation ? tsize : 0); + }else{ + start.y = stop.y = offsets.t; + titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 180 : 0; + titlePos.y = offsets.t - titleOffset + (titleRotation ? 0 : tsize); + tickVector.y = -1; + anchorOffset.y = -anchorOffset.y; + switch(labelAlign){ + case "start": + labelAlign = "end"; + break; + case "end": + labelAlign = "start"; + break; + case "middle": + labelOffset.y -= size; + break; + } + } + } + + // render shapes + + this.cleanGroup(); + + try{ + var s = this.group, + c = this.scaler, + t = this.ticks, + canLabel, + f = lin.getTransformerFromModel(this.scaler), + // GFX Canvas now supports labels, so let's _not_ fallback to HTML anymore on canvas, just use + // HTML labels if explicitly asked + no rotation + no IE + no Opera + labelType = (!o.title || !titleRotation) && !rotation && this.opt.htmlLabels && !has("ie") && !has("opera") ? "html" : "gfx", + dx = tickVector.x * taMajorTick.length, + dy = tickVector.y * taMajorTick.length; + + s.createLine({ + x1: start.x, + y1: start.y, + x2: stop.x, + y2: stop.y + }).setStroke(taStroke); + + //create axis title + if(o.title){ + var axisTitle = acommon.createText[labelType]( + this.chart, + s, + titlePos.x, + titlePos.y, + "middle", + o.title, + taTitleFont, + taTitleFontColor + ); + if(labelType == "html"){ + this.htmlElements.push(axisTitle); + }else{ + //as soon as rotation is provided, labelType won't be "html" + //rotate gfx labels + axisTitle.setTransform(g.matrix.rotategAt(titleRotation, titlePos.x, titlePos.y)); + } + } + + // go out nicely instead of try/catch + if(t==null){ + this.dirty = false; + return this; + } + + arr.forEach(t.major, function(tick){ + var offset = f(tick.value), elem, + x = start.x + axisVector.x * offset, + y = start.y + axisVector.y * offset; + this.createLine(s, { + x1: x, y1: y, + x2: x + dx, + y2: y + dy + }).setStroke(taMajorTick); + if(tick.label){ + var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : { + text: tick.label, + truncated: false + }; + label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label; + elem = this.createText(labelType, + s, + x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x), + y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y), + labelAlign, + label.text, + taFont, + taFontColor + //this._cachedLabelWidth + ); + + // if bidi support was required, the textDir is "auto" and truncation + // took place, we need to update the dir of the element for cases as: + // Fool label: 111111W (W for bidi character) + // truncated label: 11... + // in this case for auto textDir the dir will be "ltr" which is wrong. + if(this.chart.truncateBidi && label.truncated){ + this.chart.truncateBidi(elem, tick.label, labelType); + } + label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType); + if(labelType == "html"){ + this.htmlElements.push(elem); + }else if(rotation){ + elem.setTransform([ + {dx: labelOffset.x, dy: labelOffset.y}, + g.matrix.rotategAt( + rotation, + x + dx + anchorOffset.x, + y + dy + anchorOffset.y + ) + ]); + } + } + }, this); + + dx = tickVector.x * taMinorTick.length; + dy = tickVector.y * taMinorTick.length; + canLabel = c.minMinorStep <= c.minor.tick * c.bounds.scale; + arr.forEach(t.minor, function(tick){ + var offset = f(tick.value), elem, + x = start.x + axisVector.x * offset, + y = start.y + axisVector.y * offset; + this.createLine(s, { + x1: x, y1: y, + x2: x + dx, + y2: y + dy + }).setStroke(taMinorTick); + if(canLabel && tick.label){ + var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : { + text: tick.label, + truncated: false + }; + label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label; + elem = this.createText(labelType, + s, + x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x), + y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y), + labelAlign, + label.text, + taFont, + taFontColor + //this._cachedLabelWidth + ); + // if bidi support was required, the textDir is "auto" and truncation + // took place, we need to update the dir of the element for cases as: + // Fool label: 111111W (W for bidi character) + // truncated label: 11... + // in this case for auto textDir the dir will be "ltr" which is wrong. + if(this.chart.getTextDir && label.truncated){ + this.chart.truncateBidi(elem, tick.label, labelType); + } + label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType); + if(labelType == "html"){ + this.htmlElements.push(elem); + }else if(rotation){ + elem.setTransform([ + {dx: labelOffset.x, dy: labelOffset.y}, + g.matrix.rotategAt( + rotation, + x + dx + anchorOffset.x, + y + dy + anchorOffset.y + ) + ]); + } + } + }, this); + + dx = tickVector.x * taMicroTick.length; + dy = tickVector.y * taMicroTick.length; + arr.forEach(t.micro, function(tick){ + var offset = f(tick.value), elem, + x = start.x + axisVector.x * offset, + y = start.y + axisVector.y * offset; + this.createLine(s, { + x1: x, y1: y, + x2: x + dx, + y2: y + dy + }).setStroke(taMicroTick); + }, this); + }catch(e){ + // squelch + } + + this.dirty = false; + return this; // dojox.charting.axis2d.Default + }, + labelTooltip: function(elem, chart, label, truncatedLabel, font, elemType){ + var modules = ["dijit/Tooltip"]; + var aroundRect = {type: "rect"}, position = ["above", "below"], + fontWidth = g._base._getTextBox(truncatedLabel, {font: font}).w || 0, + fontHeight = font ? g.normalizedLength(g.splitFontString(font).size) : 0; + if(elemType == "html"){ + lang.mixin(aroundRect, html.coords(elem.firstChild, true)); + aroundRect.width = Math.ceil(fontWidth); + aroundRect.height = Math.ceil(fontHeight); + this._events.push({ + shape: dojo, + handle: connect.connect(elem.firstChild, "onmouseover", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.show(label, aroundRect, position); + }); + }) + }); + this._events.push({ + shape: dojo, + handle: connect.connect(elem.firstChild, "onmouseout", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.hide(aroundRect); + }); + }) + }); + }else{ + var shp = elem.getShape(), + lt = html.coords(chart.node, true); + aroundRect = lang.mixin(aroundRect, { + x: shp.x - fontWidth / 2, + y: shp.y + }); + aroundRect.x += lt.x; + aroundRect.y += lt.y; + aroundRect.x = Math.round(aroundRect.x); + aroundRect.y = Math.round(aroundRect.y); + aroundRect.width = Math.ceil(fontWidth); + aroundRect.height = Math.ceil(fontHeight); + this._events.push({ + shape: elem, + handle: elem.connect("onmouseenter", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.show(label, aroundRect, position); + }); + }) + }); + this._events.push({ + shape: elem, + handle: elem.connect("onmouseleave", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.hide(aroundRect); + }); + }) + }); + } + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/axis2d/Invisible.js b/js/dojo-1.7.2/dojox/charting/axis2d/Invisible.js new file mode 100644 index 0000000..81dd739 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/axis2d/Invisible.js @@ -0,0 +1,286 @@ +//>>built +define("dojox/charting/axis2d/Invisible", ["dojo/_base/lang", "dojo/_base/declare", "./Base", "../scaler/linear", + "dojox/gfx", "dojox/lang/utils", "dojox/lang/functional", "dojo/string"], + function(lang, declare, Base, lin, g, du, df, dstring){ +/*===== +var Base = dojox.charting.axis2d.Base; +=====*/ + var merge = du.merge, + labelGap = 4, // in pixels + centerAnchorLimit = 45; // in degrees + + return declare("dojox.charting.axis2d.Invisible", Base, { + // summary: + // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details. + // + // defaultParams: Object + // The default parameters used to define any axis. + // optionalParams: Object + // Any optional parameters needed to define an axis. + + /* + // TODO: the documentation tools need these to be pre-defined in order to pick them up + // correctly, but the code here is partially predicated on whether or not the properties + // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT + + // opt: Object + // The actual options used to define this axis, created at initialization. + // scalar: Object + // The calculated helper object to tell charts how to draw an axis and any data. + // ticks: Object + // The calculated tick object that helps a chart draw the scaling on an axis. + // dirty: Boolean + // The state of the axis (whether it needs to be redrawn or not) + // scale: Number + // The current scale of the axis. + // offset: Number + // The current offset of the axis. + + opt: null, + scalar: null, + ticks: null, + dirty: true, + scale: 1, + offset: 0, + */ + defaultParams: { + vertical: false, // true for vertical axis + fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none" + fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none" + natural: false, // all tick marks should be made on natural numbers + leftBottom: true, // position of the axis, used with "vertical" + includeZero: false, // 0 should be included + fixed: true, // all labels are fixed numbers + majorLabels: true, // draw major labels + minorTicks: true, // draw minor ticks + minorLabels: true, // draw minor labels + microTicks: false, // draw micro ticks + rotation: 0 // label rotation angle in degrees + }, + optionalParams: { + min: 0, // minimal value on this axis + max: 1, // maximal value on this axis + from: 0, // visible from this value + to: 1, // visible to this value + majorTickStep: 4, // major tick step + minorTickStep: 2, // minor tick step + microTickStep: 1, // micro tick step + labels: [], // array of labels for major ticks + // with corresponding numeric values + // ordered by values + labelFunc: null, // function to compute label values + maxLabelSize: 0, // size in px. For use with labelFunc + maxLabelCharCount: 0, // size in word count. + trailingSymbol: null + + // TODO: add support for minRange! + // minRange: 1, // smallest distance from min allowed on the axis + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for an axis. + // chart: dojox.charting.Chart + // The chart the axis belongs to. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // Any optional keyword arguments to be used to define this axis. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + }, + dependOnData: function(){ + // summary: + // Find out whether or not the axis options depend on the data in the axis. + return !("min" in this.opt) || !("max" in this.opt); // Boolean + }, + clear: function(){ + // summary: + // Clear out all calculated properties on this axis; + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + delete this.scaler; + delete this.ticks; + this.dirty = true; + return this; // dojox.charting.axis2d.Default + }, + initialized: function(){ + // summary: + // Finds out if this axis has been initialized or not. + // returns: Boolean + // Whether a scaler has been calculated and if the axis is not dirty. + return "scaler" in this && !(this.dirty && this.dependOnData()); + }, + setWindow: function(scale, offset){ + // summary: + // Set the drawing "window" for the axis. + // scale: Number + // The new scale for the axis. + // offset: Number + // The new offset for the axis. + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + this.scale = scale; + this.offset = offset; + return this.clear(); // dojox.charting.axis2d.Default + }, + getWindowScale: function(){ + // summary: + // Get the current windowing scale of the axis. + return "scale" in this ? this.scale : 1; // Number + }, + getWindowOffset: function(){ + // summary: + // Get the current windowing offset for the axis. + return "offset" in this ? this.offset : 0; // Number + }, + _groupLabelWidth: function(labels, font, wcLimit){ + if(!labels.length){ + return 0; + } + if(lang.isObject(labels[0])){ + labels = df.map(labels, function(label){ return label.text; }); + } + if (wcLimit) { + labels = df.map(labels, function(label){ + return lang.trim(label).length == 0 ? "" : label.substring(0, wcLimit) + this.trailingSymbol; + }, this); + } + var s = labels.join("<br>"); + return g._base._getTextBox(s, {font: font}).w || 0; + }, + calculate: function(min, max, span, labels){ + // summary: + // Perform all calculations needed to render this axis. + // min: Number + // The smallest value represented on this axis. + // max: Number + // The largest value represented on this axis. + // span: Number + // The span in pixels over which axis calculations are made. + // labels: String[] + // Optional list of labels. + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + if(this.initialized()){ + return this; + } + var o = this.opt; + this.labels = "labels" in o ? o.labels : labels; + this.scaler = lin.buildScaler(min, max, span, o); + var tsb = this.scaler.bounds; + if("scale" in this){ + // calculate new range + o.from = tsb.lower + this.offset; + o.to = (tsb.upper - tsb.lower) / this.scale + o.from; + // make sure that bounds are correct + if( !isFinite(o.from) || + isNaN(o.from) || + !isFinite(o.to) || + isNaN(o.to) || + o.to - o.from >= tsb.upper - tsb.lower + ){ + // any error --- remove from/to bounds + delete o.from; + delete o.to; + delete this.scale; + delete this.offset; + }else{ + // shift the window, if we are out of bounds + if(o.from < tsb.lower){ + o.to += tsb.lower - o.from; + o.from = tsb.lower; + }else if(o.to > tsb.upper){ + o.from += tsb.upper - o.to; + o.to = tsb.upper; + } + // update the offset + this.offset = o.from - tsb.lower; + } + // re-calculate the scaler + this.scaler = lin.buildScaler(min, max, span, o); + tsb = this.scaler.bounds; + // cleanup + if(this.scale == 1 && this.offset == 0){ + delete this.scale; + delete this.offset; + } + } + + var ta = this.chart.theme.axis, labelWidth = 0, rotation = o.rotation % 360, + // TODO: we use one font --- of major tick, we need to use major and minor fonts + taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), + sinr = Math.abs(Math.sin(rotation * Math.PI / 180)); + + if(rotation < 0){ + rotation += 360; + } + + if(size){ + if(this.vertical ? rotation != 0 && rotation != 180 : rotation != 90 && rotation != 270){ + // we need width of all labels + if(this.labels){ + labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount); + }else{ + var labelLength = Math.ceil( + Math.log( + Math.max( + Math.abs(tsb.from), + Math.abs(tsb.to) + ) + ) / Math.LN10 + ), + t = []; + if(tsb.from < 0 || tsb.to < 0){ + t.push("-"); + } + t.push(dstring.rep("9", labelLength)); + var precision = Math.floor( + Math.log( tsb.to - tsb.from ) / Math.LN10 + ); + if(precision > 0){ + t.push("."); + t.push(dstring.rep("9", precision)); + } + labelWidth = g._base._getTextBox( + t.join(""), + { font: taFont } + ).w; + } + labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth; + }else{ + labelWidth = size; + } + switch(rotation){ + case 0: + case 90: + case 180: + case 270: + // trivial cases: use labelWidth + break; + default: + // rotated labels + var gap1 = Math.sqrt(labelWidth * labelWidth + size * size), // short labels + gap2 = this.vertical ? size * cosr + labelWidth * sinr : labelWidth * cosr + size * sinr; // slanted labels + labelWidth = Math.min(gap1, gap2); + break; + } + } + + this.scaler.minMinorStep = labelWidth + labelGap; + this.ticks = lin.buildTicks(this.scaler, o); + return this; // dojox.charting.axis2d.Default + }, + getScaler: function(){ + // summary: + // Get the pre-calculated scaler object. + return this.scaler; // Object + }, + getTicks: function(){ + // summary: + // Get the pre-calculated ticks object. + return this.ticks; // Object + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/axis2d/common.js b/js/dojo-1.7.2/dojox/charting/axis2d/common.js new file mode 100644 index 0000000..2bb7e15 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/axis2d/common.js @@ -0,0 +1,162 @@ +//>>built +define("dojox/charting/axis2d/common", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/window", "dojo/dom-geometry", "dojox/gfx"], + function(lang, html, win, domGeom, g){ + + var common = lang.getObject("dojox.charting.axis2d.common", true); + + var clearNode = function(s){ + s.marginLeft = "0px"; + s.marginTop = "0px"; + s.marginRight = "0px"; + s.marginBottom = "0px"; + s.paddingLeft = "0px"; + s.paddingTop = "0px"; + s.paddingRight = "0px"; + s.paddingBottom = "0px"; + s.borderLeftWidth = "0px"; + s.borderTopWidth = "0px"; + s.borderRightWidth = "0px"; + s.borderBottomWidth = "0px"; + }; + + var getBoxWidth = function(n){ + // marginBox is incredibly slow, so avoid it if we can + if(n["getBoundingClientRect"]){ + var bcr = n.getBoundingClientRect(); + return bcr.width || (bcr.right - bcr.left); + }else{ + return domGeom.getMarginBox(n).w; + } + }; + + return lang.mixin(common, { + // summary: + // Common methods to be used by any axis. This is considered "static". + createText: { + gfx: function(chart, creator, x, y, align, text, font, fontColor){ + // summary: + // Use dojox.gfx to create any text. + // chart: dojox.charting.Chart + // The chart to create the text into. + // creator: dojox.gfx.Surface + // The graphics surface to use for creating the text. + // x: Number + // Where to create the text along the x axis (CSS left). + // y: Number + // Where to create the text along the y axis (CSS top). + // align: String + // How to align the text. Can be "left", "right", "center". + // text: String + // The text to render. + // font: String + // The font definition, a la CSS "font". + // fontColor: String|dojo.Color + // The color of the resultant text. + // returns: dojox.gfx.Text + // The resultant GFX object. + return creator.createText({ + x: x, y: y, text: text, align: align + }).setFont(font).setFill(fontColor); // dojox.gfx.Text + }, + html: function(chart, creator, x, y, align, text, font, fontColor, labelWidth){ + // summary: + // Use the HTML DOM to create any text. + // chart: dojox.charting.Chart + // The chart to create the text into. + // creator: dojox.gfx.Surface + // The graphics surface to use for creating the text. + // x: Number + // Where to create the text along the x axis (CSS left). + // y: Number + // Where to create the text along the y axis (CSS top). + // align: String + // How to align the text. Can be "left", "right", "center". + // text: String + // The text to render. + // font: String + // The font definition, a la CSS "font". + // fontColor: String|dojo.Color + // The color of the resultant text. + // labelWidth: Number? + // The maximum width of the resultant DOM node. + // returns: DOMNode + // The resultant DOMNode (a "div" element). + + // setup the text node + var p = win.doc.createElement("div"), s = p.style, boxWidth; + // bidi support, if this function exists the module was loaded + if(chart.getTextDir){ + p.dir = chart.getTextDir(text); + } + clearNode(s); + s.font = font; + p.innerHTML = String(text).replace(/\s/g, " "); + s.color = fontColor; + // measure the size + s.position = "absolute"; + s.left = "-10000px"; + win.body().appendChild(p); + var size = g.normalizedLength(g.splitFontString(font).size); + + // do we need to calculate the label width? + if(!labelWidth){ + boxWidth = getBoxWidth(p); + } + // when the textDir is rtl, but the UI ltr needs + // to recalculate the starting point + if(p.dir == "rtl"){ + x += labelWidth ? labelWidth : boxWidth; + } + + // new settings for the text node + win.body().removeChild(p); + + s.position = "relative"; + if(labelWidth){ + s.width = labelWidth + "px"; + // s.border = "1px dotted grey"; + switch(align){ + case "middle": + s.textAlign = "center"; + s.left = (x - labelWidth / 2) + "px"; + break; + case "end": + s.textAlign = "right"; + s.left = (x - labelWidth) + "px"; + break; + default: + s.left = x + "px"; + s.textAlign = "left"; + break; + } + }else{ + switch(align){ + case "middle": + s.left = Math.floor(x - boxWidth / 2) + "px"; + // s.left = Math.floor(x - p.offsetWidth / 2) + "px"; + break; + case "end": + s.left = Math.floor(x - boxWidth) + "px"; + // s.left = Math.floor(x - p.offsetWidth) + "px"; + break; + //case "start": + default: + s.left = Math.floor(x) + "px"; + break; + } + } + s.top = Math.floor(y - size) + "px"; + s.whiteSpace = "nowrap"; // hack for WebKit + // setup the wrapper node + var wrap = win.doc.createElement("div"), w = wrap.style; + clearNode(w); + w.width = "0px"; + w.height = "0px"; + // insert nodes + wrap.appendChild(p) + chart.node.insertBefore(wrap, chart.node.firstChild); + return wrap; // DOMNode + } + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Areas.js b/js/dojo-1.7.2/dojox/charting/plot2d/Areas.js new file mode 100644 index 0000000..a99fa7f --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Areas.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/plot2d/Areas", ["dojo/_base/declare", "./Default"], + function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + return declare("dojox.charting.plot2d.Areas", Default, { + // summary: + // Represents an area chart. See dojox.charting.plot2d.Default for details. + constructor: function(){ + this.opt.lines = true; + this.opt.areas = true; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Bars.js b/js/dojo-1.7.2/dojox/charting/plot2d/Bars.js new file mode 100644 index 0000000..375b5d4 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Bars.js @@ -0,0 +1,196 @@ +//>>built +define("dojox/charting/plot2d/Bars", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/gfx/fx", "dojox/lang/utils", "dojox/lang/functional", "dojox/lang/functional/reversed"], + function(dojo, lang, arr, declare, Base, dc, fx, du, df, dfr){ + + /*===== + dojo.declare("dojox.charting.plot2d.__BarCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { + // summary: + // Additional keyword arguments for bar charts. + + // minBarSize: Number? + // The minimum size for a bar in pixels. Default is 1. + minBarSize: 1, + + // maxBarSize: Number? + // The maximum size for a bar in pixels. Default is 1. + maxBarSize: 1, + + // enableCache: Boolean? + // Whether the bars rect are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. Default false. + enableCache: false + }); + var Base = dojox.charting.plot2d.Base; + =====*/ + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Bars", Base, { + // summary: + // The plot object representing a bar chart (horizontal bars). + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 0, // gap between columns in pixels + animate: null, // animate bars into place + enableCache: false + }, + optionalParams: { + minBarSize: 1, // minimal bar width in pixels + maxBarSize: 1, // maximal bar width in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a bar chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectSimpleStats(this.series), t; + stats.hmin -= 0.5; + stats.hmax += 0.5; + t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; + t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; + return stats; + }, + + createRect: function(run, creator, params){ + var rect; + if(this.opt.enableCache && run._rectFreePool.length > 0){ + rect = run._rectFreePool.pop(); + rect.setShape(params); + // was cleared, add it back + creator.add(rect); + }else{ + rect = creator.createRect(params); + } + if(this.opt.enableCache){ + run._rectUsePool.push(rect); + } + return rect; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Bars + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.dirty = this.isDirty(); + this.resetEvents(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, height, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._hScaler.bounds.lower), + baselineWidth = ht(baseline), + events = this.events(); + f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt); + gap = f.gap; + height = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(this.opt.enableCache){ + run._rectFreePool = (run._rectFreePool?run._rectFreePool:[]).concat(run._rectUsePool?run._rectUsePool:[]); + run._rectUsePool = []; + } + var theme = t.next("bar", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + hv = ht(v), + width = hv - baselineWidth, + w = Math.abs(width), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "bar", value, true) : + t.post(theme, "bar"); + if(w >= 0 && height >= 1){ + var rect = { + x: offsets.l + (v < baseline ? hv : baselineWidth), + y: dim.height - offsets.b - vt(j + 1.5) + gap, + width: w, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = this.createRect(run, s, rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "bar", + index: j, + run: run, + shape: shape, + x: v, + y: j + 1.5 + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateBar(shape, offsets.l + baselineWidth, -w); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Bars + }, + _animateBar: function(shape, hoffset, hsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [hoffset - (hoffset/hsize), 0], end: [0, 0]}, + {name: "scale", start: [1/hsize, 1], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Base.js b/js/dojo-1.7.2/dojox/charting/plot2d/Base.js new file mode 100644 index 0000000..2dee3ac --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Base.js @@ -0,0 +1,245 @@ +//>>built +define("dojox/charting/plot2d/Base", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", + "../Element", "./_PlotEvents", "dojo/_base/array", + "../scaler/primitive", "./common", "dojox/gfx/fx"], + function(lang, declare, hub, Element, PlotEvents, arr, primitive, common, fx){ +/*===== +var Element = dojox.charting.Element; +var PlotEvents = dojox.charting.plot2d._PlotEvents; +dojox.charting.plot2d.__PlotCtorArgs = function(){ + // summary: + // The base keyword arguments object for plot constructors. + // Note that the parameters for this may change based on the + // specific plot type (see the corresponding plot type for + // details). +} +=====*/ +return declare("dojox.charting.plot2d.Base", [Element, PlotEvents], { + constructor: function(chart, kwArgs){ + // summary: + // Create a base plot for charting. + // chart: dojox.chart.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__PlotCtorArgs? + // An optional arguments object to help define the plot. + this.zoom = null, + this.zoomQueue = []; // zooming action task queue + this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0}; + }, + clear: function(){ + // summary: + // Clear out all of the information tied to this plot. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.series = []; + this._hAxis = null; + this._vAxis = null; + this.dirty = true; + return this; // dojox.charting.plot2d.Base + }, + setAxis: function(axis){ + // summary: + // Set an axis for this plot. + // axis: dojox.charting.axis2d.Base + // The axis to set. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + if(axis){ + this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; + } + return this; // dojox.charting.plot2d.Base + }, + toPage: function(coord){ + // summary: + // Compute page coordinates from plot axis data coordinates. + // coord: Object? + // The coordinates in plot axis data coordinate space. For cartesian charts that is of the following form: + // `{ hAxisName: 50, vAxisName: 200 }` + // If not provided return the tranform method instead of the result of the transformation. + // returns: Object + // The resulting page pixel coordinates. That is of the following form: + // `{ x: 50, y: 200 }` + var ah = this._hAxis, av = this._vAxis, + sh = ah.getScaler(), sv = av.getScaler(), + th = sh.scaler.getTransformerFromModel(sh), + tv = sv.scaler.getTransformerFromModel(sv), + c = this.chart.getCoords(), + o = this.chart.offsets, dim = this.chart.dim; + var t = function(coord){ + var r = {}; + r.x = th(coord[ah.name]) + c.x + o.l; + r.y = c.y + dim.height - o.b - tv(coord[av.name]); + return r; + }; + // if no coord return the function so that we can capture the current transforms + // and reuse them later on + return coord?t(coord):t; + }, + toData: function(coord){ + // summary: + // Compute plot axis data coordinates from page coordinates. + // coord: Object + // The pixel coordinate in page coordinate space. That is of the following form: + // `{ x: 50, y: 200 }` + // If not provided return the tranform method instead of the result of the transformation. + // returns: Object + // The resulting plot axis data coordinates. For cartesian charts that is of the following form: + // `{ hAxisName: 50, vAxisName: 200 }` + var ah = this._hAxis, av = this._vAxis, + sh = ah.getScaler(), sv = av.getScaler(), + th = sh.scaler.getTransformerFromPlot(sh), + tv = sv.scaler.getTransformerFromPlot(sv), + c = this.chart.getCoords(), + o = this.chart.offsets, dim = this.chart.dim; + var t = function(coord){ + var r = {}; + r[ah.name] = th(coord.x - c.x - o.l); + r[av.name] = tv(c.y + dim.height - coord.y - o.b); + return r; + }; + // if no coord return the function so that we can capture the current transforms + // and reuse them later on + return coord?t(coord):t; + }, + addSeries: function(run){ + // summary: + // Add a data series to this plot. + // run: dojox.charting.Series + // The series to be added. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.series.push(run); + return this; // dojox.charting.plot2d.Base + }, + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return common.collectSimpleStats(this.series); + }, + calculateAxes: function(dim){ + // summary: + // Stub function for running the axis calculations (depricated). + // dim: Object + // An object of the form { width, height } + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.initializeScalers(dim, this.getSeriesStats()); + return this; // dojox.charting.plot2d.Base + }, + isDirty: function(){ + // summary: + // Returns whether or not this plot needs to be rendered. + // returns: Boolean + // The state of the plot. + return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean + }, + isDataDirty: function(){ + // summary: + // Returns whether or not any of this plot's data series need to be rendered. + // returns: Boolean + // Flag indicating if any of this plot's series are invalid and need rendering. + return arr.some(this.series, function(item){ return item.dirty; }); // Boolean + }, + performZoom: function(dim, offsets){ + // summary: + // Create/alter any zooming windows on this plot. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + + // get current zooming various + var vs = this._vAxis.scale || 1, + hs = this._hAxis.scale || 1, + vOffset = dim.height - offsets.b, + hBounds = this._hScaler.bounds, + xOffset = (hBounds.from - hBounds.lower) * hBounds.scale, + vBounds = this._vScaler.bounds, + yOffset = (vBounds.from - vBounds.lower) * vBounds.scale, + // get incremental zooming various + rVScale = vs / this.lastWindow.vscale, + rHScale = hs / this.lastWindow.hscale, + rXOffset = (this.lastWindow.xoffset - xOffset)/ + ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale), + rYOffset = (yOffset - this.lastWindow.yoffset)/ + ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale), + + shape = this.group, + anim = fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform:[ + {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]}, + {name:"scale", start:[1, 1], end: [rHScale, rVScale]}, + {name:"original"}, + {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]} + ]}, this.zoom)); + + lang.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset}); + //add anim to zooming action queue, + //in order to avoid several zooming action happened at the same time + this.zoomQueue.push(anim); + //perform each anim one by one in zoomQueue + hub.connect(anim, "onEnd", this, function(){ + this.zoom = null; + this.zoomQueue.shift(); + if(this.zoomQueue.length > 0){ + this.zoomQueue[0].play(); + } + }); + if(this.zoomQueue.length == 1){ + this.zoomQueue[0].play(); + } + return this; // dojox.charting.plot2d.Base + }, + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Base + }, + getRequiredColors: function(){ + // summary: + // Get how many data series we have, so we know how many colors to use. + // returns: Number + // The number of colors needed. + return this.series.length; // Number + }, + initializeScalers: function(dim, stats){ + // summary: + // Initializes scalers using attached axes. + // dim: Object: + // Size of a plot area in pixels as {width, height}. + // stats: Object: + // Min/max of data in both directions as {hmin, hmax, vmin, vmax}. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + if(this._hAxis){ + if(!this._hAxis.initialized()){ + this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); + } + this._hScaler = this._hAxis.getScaler(); + }else{ + this._hScaler = primitive.buildScaler(stats.hmin, stats.hmax, dim.width); + } + if(this._vAxis){ + if(!this._vAxis.initialized()){ + this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); + } + this._vScaler = this._vAxis.getScaler(); + }else{ + this._vScaler = primitive.buildScaler(stats.vmin, stats.vmax, dim.height); + } + return this; // dojox.charting.plot2d.Base + } +}); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Bubble.js b/js/dojo-1.7.2/dojox/charting/plot2d/Bubble.js new file mode 100644 index 0000000..4de7a06 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Bubble.js @@ -0,0 +1,219 @@ +//>>built +define("dojox/charting/plot2d/Bubble", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", + "./Base", "./common", "dojox/lang/functional", "dojox/lang/functional/reversed", + "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, arr, Base, dc, df, dfr, du, fx){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Bubble", Base, { + // summary: + // A plot representing bubbles. Note that data for Bubbles requires 3 parameters, + // in the form of: { x, y, size }, where size determines the size of the bubble. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + animate: null // animate bars into place + }, + optionalParams: { + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create a plot of bubbles. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs? + // Optional keyword arguments object to help define plot parameters. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + // override the render so that we are plotting only circles. + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Bubble + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + + var t = this.chart.theme, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + events = this.events(); + + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(!run.data.length){ + run.dirty = false; + t.skip(); + continue; + } + + if(typeof run.data[0] == "number"){ + console.warn("dojox.charting.plot2d.Bubble: the data in the following series cannot be rendered as a bubble chart; ", run); + continue; + } + + var theme = t.next("circle", [this.opt, run]), s = run.group, + points = arr.map(run.data, function(v, i){ + return v ? { + x: ht(v.x) + offsets.l, + y: dim.height - offsets.b - vt(v.y), + radius: this._vScaler.bounds.scale * (v.size / 2) + } : null; + }, this); + + var frontCircles = null, outlineCircles = null, shadowCircles = null; + + // make shadows if needed + if(theme.series.shadow){ + shadowCircles = arr.map(points, function(item){ + if(item !== null){ + var finalTheme = t.addMixin(theme, "circle", item, true), + shadow = finalTheme.series.shadow; + var shape = s.createCircle({ + cx: item.x + shadow.dx, cy: item.y + shadow.dy, r: item.radius + }).setStroke(shadow).setFill(shadow.color); + if(this.animate){ + this._animateBubble(shape, dim.height - offsets.b, item.radius); + } + return shape; + } + return null; + }, this); + if(shadowCircles.length){ + run.dyn.shadow = shadowCircles[shadowCircles.length - 1].getStroke(); + } + } + + // make outlines if needed + if(theme.series.outline){ + outlineCircles = arr.map(points, function(item){ + if(item !== null){ + var finalTheme = t.addMixin(theme, "circle", item, true), + outline = dc.makeStroke(finalTheme.series.outline); + outline.width = 2 * outline.width + theme.series.stroke.width; + var shape = s.createCircle({ + cx: item.x, cy: item.y, r: item.radius + }).setStroke(outline); + if(this.animate){ + this._animateBubble(shape, dim.height - offsets.b, item.radius); + } + return shape; + } + return null; + }, this); + if(outlineCircles.length){ + run.dyn.outline = outlineCircles[outlineCircles.length - 1].getStroke(); + } + } + + // run through the data and add the circles. + frontCircles = arr.map(points, function(item){ + if(item !== null){ + var finalTheme = t.addMixin(theme, "circle", item, true), + rect = { + x: item.x - item.radius, + y: item.y - item.radius, + width: 2 * item.radius, + height: 2 * item.radius + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createCircle({ + cx: item.x, cy: item.y, r: item.radius + }).setFill(specialFill).setStroke(finalTheme.series.stroke); + if(this.animate){ + this._animateBubble(shape, dim.height - offsets.b, item.radius); + } + return shape; + } + return null; + }, this); + if(frontCircles.length){ + run.dyn.fill = frontCircles[frontCircles.length - 1].getFill(); + run.dyn.stroke = frontCircles[frontCircles.length - 1].getStroke(); + } + + if(events){ + var eventSeries = new Array(frontCircles.length); + arr.forEach(frontCircles, function(s, i){ + if(s !== null){ + var o = { + element: "circle", + index: i, + run: run, + shape: s, + outline: outlineCircles && outlineCircles[i] || null, + shadow: shadowCircles && shadowCircles[i] || null, + x: run.data[i].x, + y: run.data[i].y, + r: run.data[i].size / 2, + cx: points[i].x, + cy: points[i].y, + cr: points[i].radius + }; + this._connectEvents(o); + eventSeries[i] = o; + } + }, this); + this._eventSeries[run.name] = eventSeries; + }else{ + delete this._eventSeries[run.name]; + } + + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Bubble + }, + _animateBubble: function(shape, offset, size){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, offset], end: [0, 0]}, + {name: "scale", start: [0, 1/size], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Candlesticks.js b/js/dojo-1.7.2/dojox/charting/plot2d/Candlesticks.js new file mode 100644 index 0000000..a30d39b --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Candlesticks.js @@ -0,0 +1,229 @@ +//>>built +define("dojox/charting/plot2d/Candlesticks", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, arr, Base, dc, df, dfr, du, fx){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + // Candlesticks are based on the Bars plot type; we expect the following passed + // as values in a series: + // { x?, open, close, high, low, mid? } + // if x is not provided, the array index is used. + // failing to provide the OHLC values will throw an error. + return declare("dojox.charting.plot2d.Candlesticks", Base, { + // summary: + // A plot that represents typical candlesticks (financial reporting, primarily). + // Unlike most charts, the Candlestick expects data points to be represented by + // an object of the form { x?, open, close, high, low, mid? }, where both + // x and mid are optional parameters. If x is not provided, the index of the + // data array is used. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 2, // gap between columns in pixels + animate: null // animate bars into place + }, + optionalParams: { + minBarSize: 1, // minimal candle width in pixels + maxBarSize: 1, // maximal candle width in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a candlestick chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + collectStats: function(series){ + // summary: + // Collect all statistics for drawing this chart. Since the common + // functionality only assumes x and y, Candlesticks must create it's own + // stats (since data has no y value, but open/close/high/low instead). + // series: dojox.charting.Series[] + // The data series array to be drawn on this plot. + // returns: Object + // Returns an object in the form of { hmin, hmax, vmin, vmax }. + + // we have to roll our own, since we need to use all four passed + // values to figure out our stats, and common only assumes x and y. + var stats = lang.delegate(dc.defaultStats); + for(var i=0; i<series.length; i++){ + var run = series[i]; + if(!run.data.length){ continue; } + var old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, idx){ + if(val !== null){ + var x = val.x || idx + 1; + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low); + stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low); + } + }); + } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + } + return stats; // Object + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = this.collectStats(this.series); + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Candlesticks + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("candlestick", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + var finalTheme = t.addMixin(theme, "candlestick", v, true); + + // calculate the points we need for OHLC + var x = ht(v.x || (j+0.5)) + offsets.l + gap, + y = dim.height - offsets.b, + open = vt(v.open), + close = vt(v.close), + high = vt(v.high), + low = vt(v.low); + if("mid" in v){ + var mid = vt(v.mid); + } + if(low > high){ + var tmp = high; + high = low; + low = tmp; + } + + if(width >= 1){ + // draw the line and rect, set up as a group and pass that to the events. + var doFill = open > close; + var line = { x1: width/2, x2: width/2, y1: y - high, y2: y - low }, + rect = { + x: 0, y: y-Math.max(open, close), + width: width, height: Math.max(doFill ? open-close : close-open, 1) + }; + var shape = s.createGroup(); + shape.setTransform({dx: x, dy: 0 }); + var inner = shape.createGroup(); + inner.createLine(line).setStroke(finalTheme.series.stroke); + inner.createRect(rect).setStroke(finalTheme.series.stroke). + setFill(doFill ? finalTheme.series.fill : "white"); + if("mid" in v){ + // add the mid line. + inner.createLine({ + x1: (finalTheme.series.stroke.width||1), x2: width - (finalTheme.series.stroke.width || 1), + y1: y - mid, y2: y - mid + }).setStroke(doFill ? "white" : finalTheme.series.stroke); + } + + // TODO: double check this. + run.dyn.fill = finalTheme.series.fill; + run.dyn.stroke = finalTheme.series.stroke; + if(events){ + var o = { + element: "candlestick", + index: j, + run: run, + shape: inner, + x: x, + y: y-Math.max(open, close), + cx: width/2, + cy: (y-Math.max(open, close)) + (Math.max(doFill ? open-close : close-open, 1)/2), + width: width, + height: Math.max(doFill ? open-close : close-open, 1), + data: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + } + if(this.animate){ + this._animateCandlesticks(shape, y - low, high - low); + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Candlesticks + }, + _animateCandlesticks: function(shape, voffset, vsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]}, + {name: "scale", start: [1, 1/vsize], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/ClusteredBars.js b/js/dojo-1.7.2/dojox/charting/plot2d/ClusteredBars.js new file mode 100644 index 0000000..afac291 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/ClusteredBars.js @@ -0,0 +1,100 @@ +//>>built +define("dojox/charting/plot2d/ClusteredBars", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Bars", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils"], + function(lang, arr, declare, Bars, dc, df, dfr, du){ +/*===== +var Bars = dojox.charting.plot2d.Bars; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.ClusteredBars", Bars, { + // summary: + // A plot representing grouped or clustered bars (horizontal bars) + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.ClusteredBars + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, height, thickness, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._hScaler.bounds.lower), + baselineWidth = ht(baseline), + events = this.events(); + f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt, this.series.length); + gap = f.gap; + height = thickness = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i], shift = thickness * (this.series.length - i - 1); + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("bar", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + hv = ht(v), + width = hv - baselineWidth, + w = Math.abs(width), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "bar", value, true) : + t.post(theme, "bar"); + if(w >= 0 && height >= 1){ + var rect = { + x: offsets.l + (v < baseline ? hv : baselineWidth), + y: dim.height - offsets.b - vt(j + 1.5) + gap + shift, + width: w, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "bar", + index: j, + run: run, + shape: shape, + x: v, + y: j + 1.5 + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateBar(shape, offsets.l + baselineWidth, -width); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.ClusteredBars + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/ClusteredColumns.js b/js/dojo-1.7.2/dojox/charting/plot2d/ClusteredColumns.js new file mode 100644 index 0000000..b3e7d09 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/ClusteredColumns.js @@ -0,0 +1,100 @@ +//>>built +define("dojox/charting/plot2d/ClusteredColumns", ["dojo/_base/array", "dojo/_base/declare", "./Columns", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils"], + function(arr, declare, Columns, dc, df, dfr, du){ +/*===== +var Columns = dojox.charting.plot2d.Columns; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.ClusteredColumns", Columns, { + // summary: + // A plot representing grouped or clustered columns (vertical bars). + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.ClusteredColumns + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, thickness, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt, this.series.length); + gap = f.gap; + width = thickness = f.size; + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i], shift = thickness * i; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("column", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + vv = vt(v), + height = vv - baselineHeight, + h = Math.abs(height), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "column", value, true) : + t.post(theme, "column"); + if(width >= 1 && h >= 0){ + var rect = { + x: offsets.l + ht(j + 0.5) + gap + shift, + y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight), + width: width, height: h + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "column", + index: j, + run: run, + shape: shape, + x: j + 0.5, + y: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.ClusteredColumns + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Columns.js b/js/dojo-1.7.2/dojox/charting/plot2d/Columns.js new file mode 100644 index 0000000..7e25091 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Columns.js @@ -0,0 +1,180 @@ +//>>built +define("dojox/charting/plot2d/Columns", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, arr, declare, Base, dc, df, dfr, du, fx){ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + return declare("dojox.charting.plot2d.Columns", Base, { + // summary: + // The plot object representing a column chart (vertical bars). + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 0, // gap between columns in pixels + animate: null, // animate bars into place + enableCache: false + }, + optionalParams: { + minBarSize: 1, // minimal column width in pixels + maxBarSize: 1, // maximal column width in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a columns chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectSimpleStats(this.series); + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + + createRect: function(run, creator, params){ + var rect; + if(this.opt.enableCache && run._rectFreePool.length > 0){ + rect = run._rectFreePool.pop(); + rect.setShape(params); + // was cleared, add it back + creator.add(rect); + }else{ + rect = creator.createRect(params); + } + if(this.opt.enableCache){ + run._rectUsePool.push(rect); + } + return rect; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Columns + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + var t = this.getSeriesStats(); + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + min = Math.max(0, Math.floor(this._hScaler.bounds.from - 1)), max = Math.ceil(this._hScaler.bounds.to), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(this.opt.enableCache){ + run._rectFreePool = (run._rectFreePool?run._rectFreePool:[]).concat(run._rectUsePool?run._rectUsePool:[]); + run._rectUsePool = []; + } + var theme = t.next("column", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + var l = Math.min(run.data.length, max); + for(var j = min; j < l; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + vv = vt(v), + height = vv - baselineHeight, + h = Math.abs(height), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "column", value, true) : + t.post(theme, "column"); + if(width >= 1 && h >= 0){ + var rect = { + x: offsets.l + ht(j + 0.5) + gap, + y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight), + width: width, height: h + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = this.createRect(run, s, rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "column", + index: j, + run: run, + shape: shape, + x: j + 0.5, + y: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Columns + }, + _animateColumn: function(shape, voffset, vsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]}, + {name: "scale", start: [1, 1/vsize], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Default.js b/js/dojo-1.7.2/dojox/charting/plot2d/Default.js new file mode 100644 index 0000000..50434e3 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Default.js @@ -0,0 +1,377 @@ +//>>built +define("dojox/charting/plot2d/Default", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", + "./Base", "./common", "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, arr, Base, dc, df, dfr, du, fx){ + + /*===== + dojo.declare("dojox.charting.plot2d.__DefaultCtorArgs", dojox.charting.plot2d.__PlotCtorArgs, { + // summary: + // The arguments used for any/most plots. + + // hAxis: String? + // The horizontal axis name. + hAxis: "x", + + // vAxis: String? + // The vertical axis name + vAxis: "y", + + // lines: Boolean? + // Whether or not to draw lines on this plot. Defaults to true. + lines: true, + + // areas: Boolean? + // Whether or not to draw areas on this plot. Defaults to false. + areas: false, + + // markers: Boolean? + // Whether or not to draw markers at data points on this plot. Default is false. + markers: false, + + // tension: Number|String? + // Whether or not to apply 'tensioning' to the lines on this chart. + // Options include a number, "X", "x", or "S"; if a number is used, the + // simpler bezier curve calculations are used to draw the lines. If X, x or S + // is used, the more accurate smoothing algorithm is used. + tension: "", + + // animate: Boolean? + // Whether or not to animate the chart to place. + animate: false, + + // stroke: dojox.gfx.Stroke? + // An optional stroke to use for any series on the plot. + stroke: {}, + + // outline: dojox.gfx.Stroke? + // An optional stroke used to outline any series on the plot. + outline: {}, + + // shadow: dojox.gfx.Stroke? + // An optional stroke to use to draw any shadows for a series on a plot. + shadow: {}, + + // fill: dojox.gfx.Fill? + // Any fill to be used for elements on the plot (such as areas). + fill: {}, + + // font: String? + // A font definition to be used for labels and other text-based elements on the plot. + font: "", + + // fontColor: String|dojo.Color? + // The color to be used for any text-based elements on the plot. + fontColor: "", + + // markerStroke: dojo.gfx.Stroke? + // An optional stroke to use for any markers on the plot. + markerStroke: {}, + + // markerOutline: dojo.gfx.Stroke? + // An optional outline to use for any markers on the plot. + markerOutline: {}, + + // markerShadow: dojo.gfx.Stroke? + // An optional shadow to use for any markers on the plot. + markerShadow: {}, + + // markerFill: dojo.gfx.Fill? + // An optional fill to use for any markers on the plot. + markerFill: {}, + + // markerFont: String? + // An optional font definition to use for any markers on the plot. + markerFont: "", + + // markerFontColor: String|dojo.Color? + // An optional color to use for any marker text on the plot. + markerFontColor: "", + + // enableCache: Boolean? + // Whether the markers are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. Default false. + enableCache: false + }); + + var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + var DEFAULT_ANIMATION_LENGTH = 1200; // in ms + + return declare("dojox.charting.plot2d.Default", Base, { + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + lines: true, // draw lines + areas: false, // draw areas + markers: false, // draw markers + tension: "", // draw curved lines (tension is "X", "x", or "S") + animate: false, // animate chart to place + enableCache: false + }, + optionalParams: { + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "", + markerStroke: {}, + markerOutline: {}, + markerShadow: {}, + markerFill: {}, + markerFont: "", + markerFontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Return a new plot. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs? + // An optional arguments object to help define this plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + + // animation properties + this.animate = this.opt.animate; + }, + + createPath: function(run, creator, params){ + var path; + if(this.opt.enableCache && run._pathFreePool.length > 0){ + path = run._pathFreePool.pop(); + path.setShape(params); + // was cleared, add it back + creator.add(path); + }else{ + path = creator.createPath(params); + } + if(this.opt.enableCache){ + run._pathUsePool.push(path); + } + return path; + }, + + render: function(dim, offsets){ + // summary: + // Render/draw everything on this plot. + // dim: Object + // An object of the form { width, height } + // offsets: Object + // An object of the form { l, r, t, b } + // returns: dojox.charting.plot2d.Default + // A reference to this plot for functional chaining. + + // make sure all the series is not modified + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + this.group.setTransform(null); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, stroke, outline, marker, events = this.events(); + + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(this.opt.enableCache){ + run._pathFreePool = (run._pathFreePool?run._pathFreePool:[]).concat(run._pathUsePool?run._pathUsePool:[]); + run._pathUsePool = []; + } + if(!run.data.length){ + run.dirty = false; + t.skip(); + continue; + } + + var theme = t.next(this.opt.areas ? "area" : "line", [this.opt, run], true), + s = run.group, rsegments = [], startindexes = [], rseg = null, lpoly, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + eventSeries = this._eventSeries[run.name] = new Array(run.data.length); + + // optim works only for index based case + var indexed = typeof run.data[0] == "number"; + var min = indexed?Math.max(0, Math.floor(this._hScaler.bounds.from - 1)):0, + max = indexed?Math.min(run.data.length, Math.ceil(this._hScaler.bounds.to)):run.data.length; + + // split the run data into dense segments (each containing no nulls) + for(var j = min; j < max; j++){ + if(run.data[j] != null){ + if(!rseg){ + rseg = []; + startindexes.push(j); + rsegments.push(rseg); + } + rseg.push(run.data[j]); + }else{ + rseg = null; + } + } + + for(var seg = 0; seg < rsegments.length; seg++){ + if(typeof rsegments[seg][0] == "number"){ + lpoly = arr.map(rsegments[seg], function(v, i){ + return { + x: ht(i + startindexes[seg] + 1) + offsets.l, + y: dim.height - offsets.b - vt(v) + }; + }, this); + }else{ + lpoly = arr.map(rsegments[seg], function(v, i){ + return { + x: ht(v.x) + offsets.l, + y: dim.height - offsets.b - vt(v.y) + }; + }, this); + } + + var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : ""; + + if(this.opt.areas && lpoly.length > 1){ + var fill = theme.series.fill; + var apoly = lang.clone(lpoly); + if(this.opt.tension){ + var apath = "L" + apoly[apoly.length-1].x + "," + (dim.height - offsets.b) + + " L" + apoly[0].x + "," + (dim.height - offsets.b) + + " L" + apoly[0].x + "," + apoly[0].y; + run.dyn.fill = s.createPath(lpath + " " + apath).setFill(fill).getFill(); + } else { + apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); + apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); + apoly.push(lpoly[0]); + run.dyn.fill = s.createPolyline(apoly).setFill(fill).getFill(); + } + } + if(this.opt.lines || this.opt.markers){ + // need a stroke + stroke = theme.series.stroke; + if(theme.series.outline){ + outline = run.dyn.outline = dc.makeStroke(theme.series.outline); + outline.width = 2 * outline.width + stroke.width; + } + } + if(this.opt.markers){ + run.dyn.marker = theme.symbol; + } + var frontMarkers = null, outlineMarkers = null, shadowMarkers = null; + if(stroke && theme.series.shadow && lpoly.length > 1){ + var shadow = theme.series.shadow, + spoly = arr.map(lpoly, function(c){ + return {x: c.x + shadow.dx, y: c.y + shadow.dy}; + }); + if(this.opt.lines){ + if(this.opt.tension){ + run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadow).getStroke(); + } else { + run.dyn.shadow = s.createPolyline(spoly).setStroke(shadow).getStroke(); + } + } + if(this.opt.markers && theme.marker.shadow){ + shadow = theme.marker.shadow; + shadowMarkers = arr.map(spoly, function(c){ + return this.createPath(run, s, "M" + c.x + " " + c.y + " " + theme.symbol). + setStroke(shadow).setFill(shadow.color); + }, this); + } + } + if(this.opt.lines && lpoly.length > 1){ + if(outline){ + if(this.opt.tension){ + run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke(); + } else { + run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke(); + } + } + if(this.opt.tension){ + run.dyn.stroke = s.createPath(lpath).setStroke(stroke).getStroke(); + } else { + run.dyn.stroke = s.createPolyline(lpoly).setStroke(stroke).getStroke(); + } + } + if(this.opt.markers){ + frontMarkers = new Array(lpoly.length); + outlineMarkers = new Array(lpoly.length); + outline = null; + if(theme.marker.outline){ + outline = dc.makeStroke(theme.marker.outline); + outline.width = 2 * outline.width + (theme.marker.stroke ? theme.marker.stroke.width : 0); + } + arr.forEach(lpoly, function(c, i){ + var path = "M" + c.x + " " + c.y + " " + theme.symbol; + if(outline){ + outlineMarkers[i] = this.createPath(run, s, path).setStroke(outline); + } + frontMarkers[i] = this.createPath(run, s, path).setStroke(theme.marker.stroke).setFill(theme.marker.fill); + }, this); + run.dyn.markerFill = theme.marker.fill; + run.dyn.markerStroke = theme.marker.stroke; + if(events){ + arr.forEach(frontMarkers, function(s, i){ + var o = { + element: "marker", + index: i + startindexes[seg], + run: run, + shape: s, + outline: outlineMarkers[i] || null, + shadow: shadowMarkers && shadowMarkers[i] || null, + cx: lpoly[i].x, + cy: lpoly[i].y + }; + if(typeof rsegments[seg][0] == "number"){ + o.x = i + startindexes[seg] + 1; + o.y = rsegments[seg][i]; + }else{ + o.x = rsegments[seg][i].x; + o.y = rsegments[seg][i].y; + } + this._connectEvents(o); + eventSeries[i + startindexes[seg]] = o; + }, this); + }else{ + delete this._eventSeries[run.name]; + } + } + } + run.dirty = false; + } + if(this.animate){ + // grow from the bottom + var plotGroup = this.group; + fx.animateTransform(lang.delegate({ + shape: plotGroup, + duration: DEFAULT_ANIMATION_LENGTH, + transform:[ + {name:"translate", start: [0, dim.height - offsets.b], end: [0, 0]}, + {name:"scale", start: [1, 0], end:[1, 1]}, + {name:"original"} + ] + }, this.animate)).play(); + } + this.dirty = false; + return this; // dojox.charting.plot2d.Default + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Grid.js b/js/dojo-1.7.2/dojox/charting/plot2d/Grid.js new file mode 100644 index 0000000..c7631c1 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Grid.js @@ -0,0 +1,320 @@ +//>>built +define("dojox/charting/plot2d/Grid", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/array", + "../Element", "./common", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, hub, arr, Element, dc, du, fx){ + + /*===== + dojo.declare("dojox.charting.plot2d.__GridCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { + // summary: + // A special keyword arguments object that is specific to a grid "plot". + + // hMajorLines: Boolean? + // Whether to show lines at the major ticks along the horizontal axis. Default is true. + hMajorLines: true, + + // hMinorLines: Boolean? + // Whether to show lines at the minor ticks along the horizontal axis. Default is false. + hMinorLines: false, + + // vMajorLines: Boolean? + // Whether to show lines at the major ticks along the vertical axis. Default is true. + vMajorLines: true, + + // vMinorLines: Boolean? + // Whether to show lines at the major ticks along the vertical axis. Default is false. + vMinorLines: false, + + // hStripes: String? + // Whether or not to show stripes (alternating fills) along the horizontal axis. Default is "none". + hStripes: "none", + + // vStripes: String? + // Whether or not to show stripes (alternating fills) along the vertical axis. Default is "none". + vStripes: "none", + + // enableCache: Boolean? + // Whether the grid lines are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. Default false. + enableCache: false + }); + var Element = dojox.charting.plot2d.Element; + =====*/ + + return declare("dojox.charting.plot2d.Grid", Element, { + // summary: + // A "faux" plot that can be placed behind other plots to represent + // a grid against which other plots can be easily measured. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + hMajorLines: true, // draw horizontal major lines + hMinorLines: false, // draw horizontal minor lines + vMajorLines: true, // draw vertical major lines + vMinorLines: false, // draw vertical minor lines + hStripes: "none", // TBD + vStripes: "none", // TBD + animate: null, // animate bars into place + enableCache: false + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, kwArgs){ + // summary: + // Create the faux Grid plot. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__GridCtorArgs? + // An optional keyword arguments object to help define the parameters of the underlying grid. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.dirty = true; + this.animate = this.opt.animate; + this.zoom = null, + this.zoomQueue = []; // zooming action task queue + this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0}; + if(this.opt.enableCache){ + this._lineFreePool = []; + this._lineUsePool = []; + } + }, + clear: function(){ + // summary: + // Clear out any parameters set on this plot. + // returns: dojox.charting.plot2d.Grid + // The reference to this plot for functional chaining. + this._hAxis = null; + this._vAxis = null; + this.dirty = true; + return this; // dojox.charting.plot2d.Grid + }, + setAxis: function(axis){ + // summary: + // Set an axis for this plot. + // returns: dojox.charting.plot2d.Grid + // The reference to this plot for functional chaining. + if(axis){ + this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; + } + return this; // dojox.charting.plot2d.Grid + }, + addSeries: function(run){ + // summary: + // Ignored but included as a dummy method. + // returns: dojox.charting.plot2d.Grid + // The reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Grid + }, + getSeriesStats: function(){ + // summary: + // Returns default stats (irrelevant for this type of plot). + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return lang.delegate(dc.defaultStats); + }, + initializeScalers: function(){ + // summary: + // Does nothing (irrelevant for this type of plot). + return this; + }, + isDirty: function(){ + // summary: + // Return whether or not this plot needs to be redrawn. + // returns: Boolean + // If this plot needs to be rendered, this will return true. + return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean + }, + performZoom: function(dim, offsets){ + // summary: + // Create/alter any zooming windows on this plot. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Grid + // A reference to this plot for functional chaining. + + // get current zooming various + var vs = this._vAxis.scale || 1, + hs = this._hAxis.scale || 1, + vOffset = dim.height - offsets.b, + hBounds = this._hAxis.getScaler().bounds, + xOffset = (hBounds.from - hBounds.lower) * hBounds.scale, + vBounds = this._vAxis.getScaler().bounds, + yOffset = (vBounds.from - vBounds.lower) * vBounds.scale, + // get incremental zooming various + rVScale = vs / this.lastWindow.vscale, + rHScale = hs / this.lastWindow.hscale, + rXOffset = (this.lastWindow.xoffset - xOffset)/ + ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale), + rYOffset = (yOffset - this.lastWindow.yoffset)/ + ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale), + + shape = this.group, + anim = fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform:[ + {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]}, + {name:"scale", start:[1, 1], end: [rHScale, rVScale]}, + {name:"original"}, + {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]} + ]}, this.zoom)); + + lang.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset}); + //add anim to zooming action queue, + //in order to avoid several zooming action happened at the same time + this.zoomQueue.push(anim); + //perform each anim one by one in zoomQueue + hub.connect(anim, "onEnd", this, function(){ + this.zoom = null; + this.zoomQueue.shift(); + if(this.zoomQueue.length > 0){ + this.zoomQueue[0].play(); + } + }); + if(this.zoomQueue.length == 1){ + this.zoomQueue[0].play(); + } + return this; // dojox.charting.plot2d.Grid + }, + getRequiredColors: function(){ + // summary: + // Ignored but included as a dummy method. + // returns: Number + // Returns 0, since there are no series associated with this plot type. + return 0; // Number + }, + cleanGroup: function(){ + this.inherited(arguments); + if(this.opt.enableCache){ + this._lineFreePool = this._lineFreePool.concat(this._lineUsePool); + this._lineUsePool = []; + } + }, + createLine: function(creator, params){ + var line; + if(this.opt.enableCache && this._lineFreePool.length > 0){ + line = this._lineFreePool.pop(); + line.setShape(params); + // was cleared, add it back + creator.add(line); + }else{ + line = creator.createLine(params); + } + if(this.opt.enableCache){ + this._lineUsePool.push(line); + } + return line; + }, + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Grid + // A reference to this plot for functional chaining. + if(this.zoom){ + return this.performZoom(dim, offsets); + } + this.dirty = this.isDirty(); + if(!this.dirty){ return this; } + this.cleanGroup(); + var s = this.group, ta = this.chart.theme.axis; + // draw horizontal stripes and lines + try{ + var vScaler = this._vAxis.getScaler(), + vt = vScaler.scaler.getTransformerFromModel(vScaler), + ticks = this._vAxis.getTicks(); + if(ticks != null){ + if(this.opt.hMinorLines){ + arr.forEach(ticks.minor, function(tick){ + var y = dim.height - offsets.b - vt(tick.value); + var hMinorLine = this.createLine(s, { + x1: offsets.l, + y1: y, + x2: dim.width - offsets.r, + y2: y + }).setStroke(ta.minorTick); + if(this.animate){ + this._animateGrid(hMinorLine, "h", offsets.l, offsets.r + offsets.l - dim.width); + } + }, this); + } + if(this.opt.hMajorLines){ + arr.forEach(ticks.major, function(tick){ + var y = dim.height - offsets.b - vt(tick.value); + var hMajorLine = this.createLine(s, { + x1: offsets.l, + y1: y, + x2: dim.width - offsets.r, + y2: y + }).setStroke(ta.majorTick); + if(this.animate){ + this._animateGrid(hMajorLine, "h", offsets.l, offsets.r + offsets.l - dim.width); + } + }, this); + } + } + }catch(e){ + // squelch + } + // draw vertical stripes and lines + try{ + var hScaler = this._hAxis.getScaler(), + ht = hScaler.scaler.getTransformerFromModel(hScaler), + ticks = this._hAxis.getTicks(); + if(this != null){ + if(ticks && this.opt.vMinorLines){ + arr.forEach(ticks.minor, function(tick){ + var x = offsets.l + ht(tick.value); + var vMinorLine = this.createLine(s, { + x1: x, + y1: offsets.t, + x2: x, + y2: dim.height - offsets.b + }).setStroke(ta.minorTick); + if(this.animate){ + this._animateGrid(vMinorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); + } + }, this); + } + if(ticks && this.opt.vMajorLines){ + arr.forEach(ticks.major, function(tick){ + var x = offsets.l + ht(tick.value); + var vMajorLine = this.createLine(s, { + x1: x, + y1: offsets.t, + x2: x, + y2: dim.height - offsets.b + }).setStroke(ta.majorTick); + if(this.animate){ + this._animateGrid(vMajorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); + } + }, this); + } + } + }catch(e){ + // squelch + } + this.dirty = false; + return this; // dojox.charting.plot2d.Grid + }, + _animateGrid: function(shape, type, offset, size){ + var transStart = type == "h" ? [offset, 0] : [0, offset]; + var scaleStart = type == "h" ? [1/size, 1] : [1, 1/size]; + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: transStart, end: [0, 0]}, + {name: "scale", start: scaleStart, end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Lines.js b/js/dojo-1.7.2/dojox/charting/plot2d/Lines.js new file mode 100644 index 0000000..3791acf --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Lines.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/plot2d/Lines", ["dojo/_base/declare", "./Default"], function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + return declare("dojox.charting.plot2d.Lines", Default, { + // summary: + // A convenience constructor to create a typical line chart. + constructor: function(){ + // summary: + // Preset our default plot to be line-based. + this.opt.lines = true; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Markers.js b/js/dojo-1.7.2/dojox/charting/plot2d/Markers.js new file mode 100644 index 0000000..e06d0f6 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Markers.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/plot2d/Markers", ["dojo/_base/declare", "./Default"], function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default +=====*/ + return declare("dojox.charting.plot2d.Markers", Default, { + // summary: + // A convenience plot to draw a line chart with markers. + constructor: function(){ + // summary: + // Set up the plot for lines and markers. + this.opt.markers = true; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/MarkersOnly.js b/js/dojo-1.7.2/dojox/charting/plot2d/MarkersOnly.js new file mode 100644 index 0000000..c7fe493 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/MarkersOnly.js @@ -0,0 +1,16 @@ +//>>built +define("dojox/charting/plot2d/MarkersOnly", ["dojo/_base/declare", "./Default"], function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + return declare("dojox.charting.plot2d.MarkersOnly", Default, { + // summary: + // A convenience object to draw only markers (like a scatter but not quite). + constructor: function(){ + // summary: + // Set up our default plot to only have markers and no lines. + this.opt.lines = false; + this.opt.markers = true; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/OHLC.js b/js/dojo-1.7.2/dojox/charting/plot2d/OHLC.js new file mode 100644 index 0000000..264ea29 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/OHLC.js @@ -0,0 +1,214 @@ +//>>built +define("dojox/charting/plot2d/OHLC", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, arr, declare, Base, dc, df, dfr, du, fx){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + // Candlesticks are based on the Bars plot type; we expect the following passed + // as values in a series: + // { x?, open, close, high, low } + // if x is not provided, the array index is used. + // failing to provide the OHLC values will throw an error. + return declare("dojox.charting.plot2d.OHLC", Base, { + // summary: + // A plot that represents typical open/high/low/close (financial reporting, primarily). + // Unlike most charts, the Candlestick expects data points to be represented by + // an object of the form { x?, open, close, high, low, mid? }, where both + // x and mid are optional parameters. If x is not provided, the index of the + // data array is used. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 2, // gap between columns in pixels + animate: null // animate chart to place + }, + optionalParams: { + minBarSize: 1, // minimal bar size in pixels + maxBarSize: 1, // maximal bar size in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a candlestick chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + collectStats: function(series){ + // summary: + // Collect all statistics for drawing this chart. Since the common + // functionality only assumes x and y, OHLC must create it's own + // stats (since data has no y value, but open/close/high/low instead). + // series: dojox.charting.Series[] + // The data series array to be drawn on this plot. + // returns: Object + // Returns an object in the form of { hmin, hmax, vmin, vmax }. + + // we have to roll our own, since we need to use all four passed + // values to figure out our stats, and common only assumes x and y. + var stats = lang.delegate(dc.defaultStats); + for(var i=0; i<series.length; i++){ + var run = series[i]; + if(!run.data.length){ continue; } + var old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, idx){ + if(val !== null){ + var x = val.x || idx + 1; + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low); + stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low); + } + }); + } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + } + return stats; + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = this.collectStats(this.series); + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.OHLC + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("candlestick", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + var finalTheme = t.addMixin(theme, "candlestick", v, true); + + // calculate the points we need for OHLC + var x = ht(v.x || (j+0.5)) + offsets.l + gap, + y = dim.height - offsets.b, + open = vt(v.open), + close = vt(v.close), + high = vt(v.high), + low = vt(v.low); + if(low > high){ + var tmp = high; + high = low; + low = tmp; + } + + if(width >= 1){ + var hl = {x1: width/2, x2: width/2, y1: y - high, y2: y - low}, + op = {x1: 0, x2: ((width/2) + ((finalTheme.series.stroke.width||1)/2)), y1: y-open, y2: y-open}, + cl = {x1: ((width/2) - ((finalTheme.series.stroke.width||1)/2)), x2: width, y1: y-close, y2: y-close}; + var shape = s.createGroup(); + shape.setTransform({dx: x, dy: 0}); + var inner = shape.createGroup(); + inner.createLine(hl).setStroke(finalTheme.series.stroke); + inner.createLine(op).setStroke(finalTheme.series.stroke); + inner.createLine(cl).setStroke(finalTheme.series.stroke); + + // TODO: double check this. + run.dyn.stroke = finalTheme.series.stroke; + if(events){ + var o = { + element: "candlestick", + index: j, + run: run, + shape: inner, + x: x, + y: y-Math.max(open, close), + cx: width/2, + cy: (y-Math.max(open, close)) + (Math.max(open > close ? open-close : close-open, 1)/2), + width: width, + height: Math.max(open > close ? open-close : close-open, 1), + data: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + } + if(this.animate){ + this._animateOHLC(shape, y - low, high - low); + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.OHLC + }, + _animateOHLC: function(shape, voffset, vsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]}, + {name: "scale", start: [1, 1/vsize], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Pie.js b/js/dojo-1.7.2/dojox/charting/plot2d/Pie.js new file mode 100644 index 0000000..01e07b1 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Pie.js @@ -0,0 +1,491 @@ +//>>built +define("dojox/charting/plot2d/Pie", ["dojo/_base/lang", "dojo/_base/array" ,"dojo/_base/declare", + "../Element", "./_PlotEvents", "./common", "../axis2d/common", + "dojox/gfx", "dojox/gfx/matrix", "dojox/lang/functional", "dojox/lang/utils"], + function(lang, arr, declare, Element, PlotEvents, dc, da, g, m, df, du){ + + /*===== + var Element = dojox.charting.Element; + var PlotEvents = dojox.charting.plot2d._PlotEvents; + dojo.declare("dojox.charting.plot2d.__PieCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { + // summary: + // Specialized keyword arguments object for use in defining parameters on a Pie chart. + + // labels: Boolean? + // Whether or not to draw labels for each pie slice. Default is true. + labels: true, + + // ticks: Boolean? + // Whether or not to draw ticks to labels within each slice. Default is false. + ticks: false, + + // fixed: Boolean? + // TODO + fixed: true, + + // precision: Number? + // The precision at which to sum/add data values. Default is 1. + precision: 1, + + // labelOffset: Number? + // The amount in pixels by which to offset labels. Default is 20. + labelOffset: 20, + + // labelStyle: String? + // Options as to where to draw labels. Values include "default", and "columns". Default is "default". + labelStyle: "default", // default/columns + + // htmlLabels: Boolean? + // Whether or not to use HTML to render slice labels. Default is true. + htmlLabels: true, + + // radGrad: String? + // The type of radial gradient to use in rendering. Default is "native". + radGrad: "native", + + // fanSize: Number? + // The amount for a radial gradient. Default is 5. + fanSize: 5, + + // startAngle: Number? + // Where to being rendering gradients in slices, in degrees. Default is 0. + startAngle: 0, + + // radius: Number? + // The size of the radial gradient. Default is 0. + radius: 0 + }); + =====*/ + + var FUDGE_FACTOR = 0.2; // use to overlap fans + + return declare("dojox.charting.plot2d.Pie", [Element, PlotEvents], { + // summary: + // The plot that represents a typical pie chart. + defaultParams: { + labels: true, + ticks: false, + fixed: true, + precision: 1, + labelOffset: 20, + labelStyle: "default", // default/columns + htmlLabels: true, // use HTML to draw labels + radGrad: "native", // or "linear", or "fan" + fanSize: 5, // maximum fan size in degrees + startAngle: 0 // start angle for slices in degrees + }, + optionalParams: { + radius: 0, + // theme components + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "", + labelWiring: {} + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create a pie plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.run = null; + this.dyn = []; + }, + clear: function(){ + // summary: + // Clear out all of the information tied to this plot. + // returns: dojox.charting.plot2d.Pie + // A reference to this plot for functional chaining. + this.dirty = true; + this.dyn = []; + this.run = null; + return this; // dojox.charting.plot2d.Pie + }, + setAxis: function(axis){ + // summary: + // Dummy method, since axes are irrelevant with a Pie chart. + // returns: dojox.charting.plot2d.Pie + // The reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Pie + }, + addSeries: function(run){ + // summary: + // Add a series of data to this plot. + // returns: dojox.charting.plot2d.Pie + // The reference to this plot for functional chaining. + this.run = run; + return this; // dojox.charting.plot2d.Pie + }, + getSeriesStats: function(){ + // summary: + // Returns default stats (irrelevant for this type of plot). + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return lang.delegate(dc.defaultStats); + }, + initializeScalers: function(){ + // summary: + // Does nothing (irrelevant for this type of plot). + return this; + }, + getRequiredColors: function(){ + // summary: + // Return the number of colors needed to draw this plot. + return this.run ? this.run.data.length : 0; + }, + + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Pie + // A reference to this plot for functional chaining. + if(!this.dirty){ return this; } + this.resetEvents(); + this.dirty = false; + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group, t = this.chart.theme; + + if(!this.run || !this.run.data.length){ + return this; + } + + // calculate the geometry + var rx = (dim.width - offsets.l - offsets.r) / 2, + ry = (dim.height - offsets.t - offsets.b) / 2, + r = Math.min(rx, ry), + taFont = "font" in this.opt ? this.opt.font : t.axis.font, + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + taFontColor = "fontColor" in this.opt ? this.opt.fontColor : t.axis.fontColor, + startAngle = m._degToRad(this.opt.startAngle), + start = startAngle, step, filteredRun, slices, labels, shift, labelR, + run = this.run.data, + events = this.events(); + if(typeof run[0] == "number"){ + filteredRun = df.map(run, "x ? Math.max(x, 0) : 0"); + if(df.every(filteredRun, "<= 0")){ + return this; + } + slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); + if(this.opt.labels){ + labels = arr.map(slices, function(x){ + return x > 0 ? this._getLabel(x * 100) + "%" : ""; + }, this); + } + }else{ + filteredRun = df.map(run, "x ? Math.max(x.y, 0) : 0"); + if(df.every(filteredRun, "<= 0")){ + return this; + } + slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); + if(this.opt.labels){ + labels = arr.map(slices, function(x, i){ + if(x <= 0){ return ""; } + var v = run[i]; + return "text" in v ? v.text : this._getLabel(x * 100) + "%"; + }, this); + } + } + var themes = df.map(run, function(v, i){ + if(v === null || typeof v == "number"){ + return t.next("slice", [this.opt, this.run], true); + } + return t.next("slice", [this.opt, this.run, v], true); + }, this); + if(this.opt.labels){ + shift = df.foldl1(df.map(labels, function(label, i){ + var font = themes[i].series.font; + return g._base._getTextBox(label, {font: font}).w; + }, this), "Math.max(a, b)") / 2; + if(this.opt.labelOffset < 0){ + r = Math.min(rx - 2 * shift, ry - size) + this.opt.labelOffset; + } + labelR = r - this.opt.labelOffset; + } + if("radius" in this.opt){ + r = this.opt.radius; + labelR = r - this.opt.labelOffset; + } + var circle = { + cx: offsets.l + rx, + cy: offsets.t + ry, + r: r + }; + + this.dyn = []; + // draw slices + var eventSeries = new Array(slices.length); + arr.some(slices, function(slice, i){ + if(slice < 0){ + // degenerated slice + return false; // continue + } + if(slice == 0){ + this.dyn.push({fill: null, stroke: null}); + return false; + } + var v = run[i], theme = themes[i], specialFill; + if(slice >= 1){ + // whole pie + specialFill = this._plotFill(theme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, + { + x: circle.cx - circle.r, y: circle.cy - circle.r, + width: 2 * circle.r, height: 2 * circle.r + }); + specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, circle.r); + var shape = s.createCircle(circle).setFill(specialFill).setStroke(theme.series.stroke); + this.dyn.push({fill: specialFill, stroke: theme.series.stroke}); + + if(events){ + var o = { + element: "slice", + index: i, + run: this.run, + shape: shape, + x: i, + y: typeof v == "number" ? v : v.y, + cx: circle.cx, + cy: circle.cy, + cr: r + }; + this._connectEvents(o); + eventSeries[i] = o; + } + + return true; // stop iteration + } + // calculate the geometry of the slice + var end = start + slice * 2 * Math.PI; + if(i + 1 == slices.length){ + end = startAngle + 2 * Math.PI; + } + var step = end - start, + x1 = circle.cx + r * Math.cos(start), + y1 = circle.cy + r * Math.sin(start), + x2 = circle.cx + r * Math.cos(end), + y2 = circle.cy + r * Math.sin(end); + // draw the slice + var fanSize = m._degToRad(this.opt.fanSize); + if(theme.series.fill && theme.series.fill.type === "radial" && this.opt.radGrad === "fan" && step > fanSize){ + var group = s.createGroup(), nfans = Math.ceil(step / fanSize), delta = step / nfans; + specialFill = this._shapeFill(theme.series.fill, + {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r}); + for(var j = 0; j < nfans; ++j){ + var fansx = j == 0 ? x1 : circle.cx + r * Math.cos(start + (j - FUDGE_FACTOR) * delta), + fansy = j == 0 ? y1 : circle.cy + r * Math.sin(start + (j - FUDGE_FACTOR) * delta), + fanex = j == nfans - 1 ? x2 : circle.cx + r * Math.cos(start + (j + 1 + FUDGE_FACTOR) * delta), + faney = j == nfans - 1 ? y2 : circle.cy + r * Math.sin(start + (j + 1 + FUDGE_FACTOR) * delta), + fan = group.createPath(). + moveTo(circle.cx, circle.cy). + lineTo(fansx, fansy). + arcTo(r, r, 0, delta > Math.PI, true, fanex, faney). + lineTo(circle.cx, circle.cy). + closePath(). + setFill(this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start + (j + 0.5) * delta, start + (j + 0.5) * delta)); + } + group.createPath(). + moveTo(circle.cx, circle.cy). + lineTo(x1, y1). + arcTo(r, r, 0, step > Math.PI, true, x2, y2). + lineTo(circle.cx, circle.cy). + closePath(). + setStroke(theme.series.stroke); + shape = group; + }else{ + shape = s.createPath(). + moveTo(circle.cx, circle.cy). + lineTo(x1, y1). + arcTo(r, r, 0, step > Math.PI, true, x2, y2). + lineTo(circle.cx, circle.cy). + closePath(). + setStroke(theme.series.stroke); + var specialFill = theme.series.fill; + if(specialFill && specialFill.type === "radial"){ + specialFill = this._shapeFill(specialFill, {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r}); + if(this.opt.radGrad === "linear"){ + specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start, end); + } + }else if(specialFill && specialFill.type === "linear"){ + specialFill = this._plotFill(specialFill, dim, offsets); + specialFill = this._shapeFill(specialFill, shape.getBoundingBox()); + } + shape.setFill(specialFill); + } + this.dyn.push({fill: specialFill, stroke: theme.series.stroke}); + + if(events){ + var o = { + element: "slice", + index: i, + run: this.run, + shape: shape, + x: i, + y: typeof v == "number" ? v : v.y, + cx: circle.cx, + cy: circle.cy, + cr: r + }; + this._connectEvents(o); + eventSeries[i] = o; + } + + start = end; + + return false; // continue + }, this); + // draw labels + if(this.opt.labels){ + if(this.opt.labelStyle == "default"){ + start = startAngle; + arr.some(slices, function(slice, i){ + if(slice <= 0){ + // degenerated slice + return false; // continue + } + var theme = themes[i]; + if(slice >= 1){ + // whole pie + var v = run[i], elem = da.createText[this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"]( + this.chart, s, circle.cx, circle.cy + size / 2, "middle", labels[i], + theme.series.font, theme.series.fontColor); + if(this.opt.htmlLabels){ + this.htmlElements.push(elem); + } + return true; // stop iteration + } + // calculate the geometry of the slice + var end = start + slice * 2 * Math.PI, v = run[i]; + if(i + 1 == slices.length){ + end = startAngle + 2 * Math.PI; + } + var labelAngle = (start + end) / 2, + x = circle.cx + labelR * Math.cos(labelAngle), + y = circle.cy + labelR * Math.sin(labelAngle) + size / 2; + // draw the label + var elem = da.createText[this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"] + (this.chart, s, x, y, "middle", labels[i], theme.series.font, theme.series.fontColor); + if(this.opt.htmlLabels){ + this.htmlElements.push(elem); + } + start = end; + return false; // continue + }, this); + }else if(this.opt.labelStyle == "columns"){ + start = startAngle; + //calculate label angles + var labeledSlices = []; + arr.forEach(slices, function(slice, i){ + var end = start + slice * 2 * Math.PI; + if(i + 1 == slices.length){ + end = startAngle + 2 * Math.PI; + } + var labelAngle = (start + end) / 2; + labeledSlices.push({ + angle: labelAngle, + left: Math.cos(labelAngle) < 0, + theme: themes[i], + index: i, + omit: end - start < 0.001 + }); + start = end; + }); + //calculate label radius to each slice + var labelHeight = g._base._getTextBox("a",{font:taFont}).h; + this._getProperLabelRadius(labeledSlices, labelHeight, circle.r * 1.1); + //draw label and wiring + arr.forEach(labeledSlices, function(slice, i){ + if (!slice.omit) { + var leftColumn = circle.cx - circle.r * 2, + rightColumn = circle.cx + circle.r * 2, + labelWidth = g._base._getTextBox(labels[i], {font: taFont}).w, + x = circle.cx + slice.labelR * Math.cos(slice.angle), + y = circle.cy + slice.labelR * Math.sin(slice.angle), + jointX = (slice.left) ? (leftColumn + labelWidth) : (rightColumn - labelWidth), + labelX = (slice.left) ? leftColumn : jointX; + var wiring = s.createPath().moveTo(circle.cx + circle.r * Math.cos(slice.angle), circle.cy + circle.r * Math.sin(slice.angle)) + if (Math.abs(slice.labelR * Math.cos(slice.angle)) < circle.r * 2 - labelWidth) { + wiring.lineTo(x, y); + } + wiring.lineTo(jointX, y).setStroke(slice.theme.series.labelWiring); + var elem = da.createText[this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"]( + this.chart, s, labelX, y, "left", labels[i], slice.theme.series.font, slice.theme.series.fontColor); + if (this.opt.htmlLabels) { + this.htmlElements.push(elem); + } + } + },this); + } + } + // post-process events to restore the original indexing + var esi = 0; + this._eventSeries[this.run.name] = df.map(run, function(v){ + return v <= 0 ? null : eventSeries[esi++]; + }); + return this; // dojox.charting.plot2d.Pie + }, + + _getProperLabelRadius: function(slices, labelHeight, minRidius){ + var leftCenterSlice = {},rightCenterSlice = {},leftMinSIN = 1, rightMinSIN = 1; + if (slices.length == 1) { + slices[0].labelR = minRidius; + return; + } + for(var i = 0;i<slices.length;i++){ + var tempSIN = Math.abs(Math.sin(slices[i].angle)); + if(slices[i].left){ + if(leftMinSIN > tempSIN){ + leftMinSIN = tempSIN; + leftCenterSlice = slices[i]; + } + }else{ + if(rightMinSIN > tempSIN){ + rightMinSIN = tempSIN; + rightCenterSlice = slices[i]; + } + } + } + leftCenterSlice.labelR = rightCenterSlice.labelR = minRidius; + this._calculateLabelR(leftCenterSlice,slices,labelHeight); + this._calculateLabelR(rightCenterSlice,slices,labelHeight); + }, + _calculateLabelR: function(firstSlice,slices,labelHeight){ + var i = firstSlice.index,length = slices.length, + currentLabelR = firstSlice.labelR; + while(!(slices[i%length].left ^ slices[(i+1)%length].left)){ + if (!slices[(i + 1) % length].omit) { + var nextLabelR = (Math.sin(slices[i % length].angle) * currentLabelR + ((slices[i % length].left) ? (-labelHeight) : labelHeight)) / + Math.sin(slices[(i + 1) % length].angle); + currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR; + slices[(i + 1) % length].labelR = currentLabelR; + } + i++; + } + i = firstSlice.index; + var j = (i == 0)?length-1 : i - 1; + while(!(slices[i].left ^ slices[j].left)){ + if (!slices[j].omit) { + var nextLabelR = (Math.sin(slices[i].angle) * currentLabelR + ((slices[i].left) ? labelHeight : (-labelHeight))) / + Math.sin(slices[j].angle); + currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR; + slices[j].labelR = currentLabelR; + } + i--;j--; + i = (i < 0)?i+slices.length:i; + j = (j < 0)?j+slices.length:j; + } + }, + // utilities + _getLabel: function(number){ + return dc.getLabel(number, this.opt.fixed, this.opt.precision); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Scatter.js b/js/dojo-1.7.2/dojox/charting/plot2d/Scatter.js new file mode 100644 index 0000000..7f6f68c --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Scatter.js @@ -0,0 +1,189 @@ +//>>built +define("dojox/charting/plot2d/Scatter", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx", "dojox/gfx/gradutils"], + function(lang, arr, declare, Base, dc, df, dfr, du, fx, gradutils){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Scatter", Base, { + // summary: + // A plot object representing a typical scatter chart. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + shadows: null, // draw shadows + animate: null // animate chart to place + }, + optionalParams: { + // theme component + markerStroke: {}, + markerOutline: {}, + markerShadow: {}, + markerFill: {}, + markerFont: "", + markerFontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create the scatter plot. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs? + // An optional keyword arguments object to help define this plot's parameters. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Scatter + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, events = this.events(); + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(!run.data.length){ + run.dirty = false; + t.skip(); + continue; + } + + var theme = t.next("marker", [this.opt, run]), s = run.group, lpoly, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler); + if(typeof run.data[0] == "number"){ + lpoly = arr.map(run.data, function(v, i){ + return { + x: ht(i + 1) + offsets.l, + y: dim.height - offsets.b - vt(v) + }; + }, this); + }else{ + lpoly = arr.map(run.data, function(v, i){ + return { + x: ht(v.x) + offsets.l, + y: dim.height - offsets.b - vt(v.y) + }; + }, this); + } + + var shadowMarkers = new Array(lpoly.length), + frontMarkers = new Array(lpoly.length), + outlineMarkers = new Array(lpoly.length); + + arr.forEach(lpoly, function(c, i){ + var finalTheme = typeof run.data[i] == "number" ? + t.post(theme, "marker") : + t.addMixin(theme, "marker", run.data[i], true), + path = "M" + c.x + " " + c.y + " " + finalTheme.symbol; + if(finalTheme.marker.shadow){ + shadowMarkers[i] = s.createPath("M" + (c.x + finalTheme.marker.shadow.dx) + " " + + (c.y + finalTheme.marker.shadow.dy) + " " + finalTheme.symbol). + setStroke(finalTheme.marker.shadow).setFill(finalTheme.marker.shadow.color); + if(this.animate){ + this._animateScatter(shadowMarkers[i], dim.height - offsets.b); + } + } + if(finalTheme.marker.outline){ + var outline = dc.makeStroke(finalTheme.marker.outline); + outline.width = 2 * outline.width + finalTheme.marker.stroke.width; + outlineMarkers[i] = s.createPath(path).setStroke(outline); + if(this.animate){ + this._animateScatter(outlineMarkers[i], dim.height - offsets.b); + } + } + var stroke = dc.makeStroke(finalTheme.marker.stroke), + fill = this._plotFill(finalTheme.marker.fill, dim, offsets); + if(fill && (fill.type === "linear" || fill.type == "radial")){ + var color = gradutils.getColor(fill, {x: c.x, y: c.y}); + if(stroke){ + stroke.color = color; + } + frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(color); + }else{ + frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(fill); + } + if(this.animate){ + this._animateScatter(frontMarkers[i], dim.height - offsets.b); + } + }, this); + if(frontMarkers.length){ + run.dyn.stroke = frontMarkers[frontMarkers.length - 1].getStroke(); + run.dyn.fill = frontMarkers[frontMarkers.length - 1].getFill(); + } + + if(events){ + var eventSeries = new Array(frontMarkers.length); + arr.forEach(frontMarkers, function(s, i){ + var o = { + element: "marker", + index: i, + run: run, + shape: s, + outline: outlineMarkers && outlineMarkers[i] || null, + shadow: shadowMarkers && shadowMarkers[i] || null, + cx: lpoly[i].x, + cy: lpoly[i].y + }; + if(typeof run.data[0] == "number"){ + o.x = i + 1; + o.y = run.data[i]; + }else{ + o.x = run.data[i].x; + o.y = run.data[i].y; + } + this._connectEvents(o); + eventSeries[i] = o; + }, this); + this._eventSeries[run.name] = eventSeries; + }else{ + delete this._eventSeries[run.name]; + } + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Scatter + }, + _animateScatter: function(shape, offset){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, offset], end: [0, 0]}, + {name: "scale", start: [0, 0], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Spider.js b/js/dojo-1.7.2/dojox/charting/plot2d/Spider.js new file mode 100644 index 0000000..a5a67b0 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Spider.js @@ -0,0 +1,632 @@ +//>>built +define("dojox/charting/plot2d/Spider", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/html", "dojo/_base/array", + "dojo/dom-geometry", "dojo/_base/fx", "dojo/fx", "dojo/_base/sniff", + "../Element", "./_PlotEvents", "dojo/_base/Color", "dojox/color/_base", "./common", "../axis2d/common", + "../scaler/primitive", "dojox/gfx", "dojox/gfx/matrix", "dojox/gfx/fx", "dojox/lang/functional", + "dojox/lang/utils", "dojo/fx/easing"], + function(lang, declare, hub, html, arr, domGeom, baseFx, coreFx, has, + Element, PlotEvents, Color, dxcolor, dc, da, primitive, + g, m, gfxfx, df, du, easing){ +/*===== +var Element = dojox.charting.Element; +var PlotEvents = dojox.charting.plot2d._PlotEvents; +=====*/ + var FUDGE_FACTOR = 0.2; // use to overlap fans + + var Spider = declare("dojox.charting.plot2d.Spider", [Element, PlotEvents], { + // summary: + // The plot that represents a typical Spider chart. + defaultParams: { + labels: true, + ticks: false, + fixed: true, + precision: 1, + labelOffset: -10, + labelStyle: "default", // default/rows/auto + htmlLabels: true, // use HTML to draw labels + startAngle: -90, // start angle for slices in degrees + divisions: 3, // radius tick count + axisColor: "", // spider axis color + axisWidth: 0, // spider axis stroke width + spiderColor: "", // spider web color + spiderWidth: 0, // spider web stroke width + seriesWidth: 0, // plot border with + seriesFillAlpha: 0.2, // plot fill alpha + spiderOrigin: 0.16, + markerSize: 3, // radius of plot vertex (px) + spiderType: "polygon", //"circle" + animationType: easing.backOut, + axisTickFont: "", + axisTickFontColor: "", + axisFont: "", + axisFontColor: "" + }, + optionalParams: { + radius: 0, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create a Spider plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.dyn = []; + this.datas = {}; + this.labelKey = []; + this.oldSeriePoints = {}; + this.animations = {}; + }, + clear: function(){ + // summary: + // Clear out all of the information tied to this plot. + // returns: dojox.charting.plot2d.Spider + // A reference to this plot for functional chaining. + this.dirty = true; + this.dyn = []; + this.series = []; + this.datas = {}; + this.labelKey = []; + this.oldSeriePoints = {}; + this.animations = {}; + return this; // dojox.charting.plot2d.Spider + }, + setAxis: function(axis){ + // summary: + // Dummy method, since axes are irrelevant with a Spider chart. + // returns: dojox.charting.plot2d.Spider + // The reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Spider + }, + addSeries: function(run){ + // summary: + // Add a data series to this plot. + // run: dojox.charting.Series + // The series to be added. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + var matched = false; + this.series.push(run); + for(var key in run.data){ + var val = run.data[key], + data = this.datas[key]; + if(data){ + data.vlist.push(val); + data.min = Math.min(data.min, val); + data.max = Math.max(data.max, val); + }else{ + this.datas[key] = {min: val, max: val, vlist: [val]}; + } + } + if (this.labelKey.length <= 0) { + for (var key in run.data) { + this.labelKey.push(key); + } + } + return this; // dojox.charting.plot2d.Base + }, + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return dc.collectSimpleStats(this.series); + }, + calculateAxes: function(dim){ + // summary: + // Stub function for running the axis calculations (depricated). + // dim: Object + // An object of the form { width, height } + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.initializeScalers(dim, this.getSeriesStats()); + return this; // dojox.charting.plot2d.Base + }, + getRequiredColors: function(){ + // summary: + // Get how many data series we have, so we know how many colors to use. + // returns: Number + // The number of colors needed. + return this.series.length; // Number + }, + initializeScalers: function(dim, stats){ + // summary: + // Initializes scalers using attached axes. + // dim: Object: + // Size of a plot area in pixels as {width, height}. + // stats: Object: + // Min/max of data in both directions as {hmin, hmax, vmin, vmax}. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + if(this._hAxis){ + if(!this._hAxis.initialized()){ + this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); + } + this._hScaler = this._hAxis.getScaler(); + }else{ + this._hScaler = primitive.buildScaler(stats.hmin, stats.hmax, dim.width); + } + if(this._vAxis){ + if(!this._vAxis.initialized()){ + this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); + } + this._vScaler = this._vAxis.getScaler(); + }else{ + this._vScaler = primitive.buildScaler(stats.vmin, stats.vmax, dim.height); + } + return this; // dojox.charting.plot2d.Base + }, + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Spider + // A reference to this plot for functional chaining. + if(!this.dirty){ return this; } + this.dirty = false; + this.cleanGroup(); + var s = this.group, t = this.chart.theme; + this.resetEvents(); + + if(!this.series || !this.series.length){ + return this; + } + + // calculate the geometry + var o = this.opt, ta = t.axis, + rx = (dim.width - offsets.l - offsets.r) / 2, + ry = (dim.height - offsets.t - offsets.b) / 2, + r = Math.min(rx, ry), + axisTickFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font) || "normal normal normal 7pt Tahoma", + axisFont = o.axisFont || (ta.tick && ta.tick.titleFont) || "normal normal normal 11pt Tahoma", + axisTickFontColor = o.axisTickFontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "silver", + axisFontColor = o.axisFontColor || (ta.tick && ta.tick.titleFontColor) || "black", + axisColor = o.axisColor || (ta.tick && ta.tick.axisColor) || "silver", + spiderColor = o.spiderColor || (ta.tick && ta.tick.spiderColor) || "silver", + axisWidth = o.axisWidth || (ta.stroke && ta.stroke.width) || 2, + spiderWidth = o.spiderWidth || (ta.stroke && ta.stroke.width) || 2, + seriesWidth = o.seriesWidth || (ta.stroke && ta.stroke.width) || 2, + asize = g.normalizedLength(g.splitFontString(axisFont).size), + startAngle = m._degToRad(o.startAngle), + start = startAngle, step, filteredRun, slices, labels, shift, labelR, + outerPoints, innerPoints, divisionPoints, divisionRadius, labelPoints, + ro = o.spiderOrigin, dv = o.divisions >= 3 ? o.divisions : 3, ms = o.markerSize, + spt = o.spiderType, at = o.animationType, lboffset = o.labelOffset < -10 ? o.labelOffset : -10, + axisExtra = 0.2; + + if(o.labels){ + labels = arr.map(this.series, function(s){ + return s.name; + }, this); + shift = df.foldl1(df.map(labels, function(label, i){ + var font = t.series.font; + return g._base._getTextBox(label, { + font: font + }).w; + }, this), "Math.max(a, b)") / 2; + r = Math.min(rx - 2 * shift, ry - asize) + lboffset; + labelR = r - lboffset; + } + if ("radius" in o) { + r = o.radius; + labelR = r - lboffset; + } + r /= (1+axisExtra); + var circle = { + cx: offsets.l + rx, + cy: offsets.t + ry, + r: r + }; + + for (var i = this.series.length - 1; i >= 0; i--) { + var serieEntry = this.series[i]; + if (!this.dirty && !serieEntry.dirty) { + t.skip(); + continue; + } + serieEntry.cleanGroup(); + var run = serieEntry.data; + if (run !== null) { + var len = this._getObjectLength(run); + //construct connect points + if (!outerPoints || outerPoints.length <= 0) { + outerPoints = [], innerPoints = [], labelPoints = []; + this._buildPoints(outerPoints, len, circle, r, start, true); + this._buildPoints(innerPoints, len, circle, r*ro, start, true); + this._buildPoints(labelPoints, len, circle, labelR, start); + if(dv > 2){ + divisionPoints = [], divisionRadius = []; + for (var j = 0; j < dv - 2; j++) { + divisionPoints[j] = []; + this._buildPoints(divisionPoints[j], len, circle, r*(ro + (1-ro)*(j+1)/(dv-1)), start, true); + divisionRadius[j] = r*(ro + (1-ro)*(j+1)/(dv-1)); + } + } + } + } + } + + //draw Spider + //axis + var axisGroup = s.createGroup(), axisStroke = {color: axisColor, width: axisWidth}, + spiderStroke = {color: spiderColor, width: spiderWidth}; + for (var j = outerPoints.length - 1; j >= 0; --j) { + var point = outerPoints[j], + st = { + x: point.x + (point.x - circle.cx) * axisExtra, + y: point.y + (point.y - circle.cy) * axisExtra + }, + nd = { + x: point.x + (point.x - circle.cx) * axisExtra / 2, + y: point.y + (point.y - circle.cy) * axisExtra / 2 + }; + axisGroup.createLine({ + x1: circle.cx, + y1: circle.cy, + x2: st.x, + y2: st.y + }).setStroke(axisStroke); + //arrow + this._drawArrow(axisGroup, st, nd, axisStroke); + } + + // draw the label + var labelGroup = s.createGroup(); + for (var j = labelPoints.length - 1; j >= 0; --j) { + var point = labelPoints[j], + fontWidth = g._base._getTextBox(this.labelKey[j], {font: axisFont}).w || 0, + render = this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx", + elem = da.createText[render](this.chart, labelGroup, (!domGeom.isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y, + "middle", this.labelKey[j], axisFont, axisFontColor); + if (this.opt.htmlLabels) { + this.htmlElements.push(elem); + } + } + + //spider web: polygon or circle + var spiderGroup = s.createGroup(); + if(spt == "polygon"){ + spiderGroup.createPolyline(outerPoints).setStroke(spiderStroke); + spiderGroup.createPolyline(innerPoints).setStroke(spiderStroke); + if (divisionPoints.length > 0) { + for (var j = divisionPoints.length - 1; j >= 0; --j) { + spiderGroup.createPolyline(divisionPoints[j]).setStroke(spiderStroke); + } + } + }else{//circle + var ccount = this._getObjectLength(this.datas); + spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r}).setStroke(spiderStroke); + spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r*ro}).setStroke(spiderStroke); + if (divisionRadius.length > 0) { + for (var j = divisionRadius.length - 1; j >= 0; --j) { + spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: divisionRadius[j]}).setStroke(spiderStroke); + } + } + } + //text + var textGroup = s.createGroup(), len = this._getObjectLength(this.datas), k = 0; + for(var key in this.datas){ + var data = this.datas[key], min = data.min, max = data.max, distance = max - min, + end = start + 2 * Math.PI * k / len; + for (var i = 0; i < dv; i++) { + var text = min + distance*i/(dv-1), point = this._getCoordinate(circle, r*(ro + (1-ro)*i/(dv-1)), end); + text = this._getLabel(text); + var fontWidth = g._base._getTextBox(text, {font: axisTickFont}).w || 0, + render = this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"; + if (this.opt.htmlLabels) { + this.htmlElements.push(da.createText[render] + (this.chart, textGroup, (!domGeom.isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y, + "start", text, axisTickFont, axisTickFontColor)); + } + } + k++; + } + + //draw series (animation) + this.chart.seriesShapes = {}; + var animationConnections = []; + for (var i = this.series.length - 1; i >= 0; i--) { + var serieEntry = this.series[i], run = serieEntry.data; + if (run !== null) { + //series polygon + var seriePoints = [], k = 0, tipData = []; + for(var key in run){ + var data = this.datas[key], min = data.min, max = data.max, distance = max - min, + entry = run[key], end = start + 2 * Math.PI * k / len, + point = this._getCoordinate(circle, r*(ro + (1-ro)*(entry-min)/distance), end); + seriePoints.push(point); + tipData.push({sname: serieEntry.name, key: key, data: entry}); + k++; + } + seriePoints[seriePoints.length] = seriePoints[0]; + tipData[tipData.length] = tipData[0]; + var polygonBoundRect = this._getBoundary(seriePoints), + theme = t.next("spider", [o, serieEntry]), ts = serieEntry.group, + f = g.normalizeColor(theme.series.fill), sk = {color: theme.series.fill, width: seriesWidth}; + f.a = o.seriesFillAlpha; + serieEntry.dyn = {fill: f, stroke: sk}; + + var osps = this.oldSeriePoints[serieEntry.name]; + var cs = this._createSeriesEntry(ts, (osps || innerPoints), seriePoints, f, sk, r, ro, ms, at); + this.chart.seriesShapes[serieEntry.name] = cs; + this.oldSeriePoints[serieEntry.name] = seriePoints; + + var po = { + element: "spider_poly", + index: i, + id: "spider_poly_"+serieEntry.name, + run: serieEntry, + plot: this, + shape: cs.poly, + parent: ts, + brect: polygonBoundRect, + cx: circle.cx, + cy: circle.cy, + cr: r, + f: f, + s: s + }; + this._connectEvents(po); + + var so = { + element: "spider_plot", + index: i, + id: "spider_plot_"+serieEntry.name, + run: serieEntry, + plot: this, + shape: serieEntry.group + }; + this._connectEvents(so); + + arr.forEach(cs.circles, function(c, i){ + var shape = c.getShape(), + co = { + element: "spider_circle", + index: i, + id: "spider_circle_"+serieEntry.name+i, + run: serieEntry, + plot: this, + shape: c, + parent: ts, + tdata: tipData[i], + cx: seriePoints[i].x, + cy: seriePoints[i].y, + f: f, + s: s + }; + this._connectEvents(co); + }, this); + } + } + return this; // dojox.charting.plot2d.Spider + }, + _createSeriesEntry: function(ts, osps, sps, f, sk, r, ro, ms, at){ + //polygon + var spoly = ts.createPolyline(osps).setFill(f).setStroke(sk), scircle = []; + for (var j = 0; j < osps.length; j++) { + var point = osps[j], cr = ms; + var circle = ts.createCircle({cx: point.x, cy: point.y, r: cr}).setFill(f).setStroke(sk); + scircle.push(circle); + } + + var anims = arr.map(sps, function(np, j){ + // create animation + var sp = osps[j], + anim = new baseFx.Animation({ + duration: 1000, + easing: at, + curve: [sp.y, np.y] + }); + var spl = spoly, sc = scircle[j]; + hub.connect(anim, "onAnimate", function(y){ + //apply poly + var pshape = spl.getShape(); + pshape.points[j].y = y; + spl.setShape(pshape); + //apply circle + var cshape = sc.getShape(); + cshape.cy = y; + sc.setShape(cshape); + }); + return anim; + }); + + var anims1 = arr.map(sps, function(np, j){ + // create animation + var sp = osps[j], + anim = new baseFx.Animation({ + duration: 1000, + easing: at, + curve: [sp.x, np.x] + }); + var spl = spoly, sc = scircle[j]; + hub.connect(anim, "onAnimate", function(x){ + //apply poly + var pshape = spl.getShape(); + pshape.points[j].x = x; + spl.setShape(pshape); + //apply circle + var cshape = sc.getShape(); + cshape.cx = x; + sc.setShape(cshape); + }); + return anim; + }); + var masterAnimation = coreFx.combine(anims.concat(anims1)); //dojo.fx.chain(anims); + masterAnimation.play(); + return {group :ts, poly: spoly, circles: scircle}; + }, + plotEvent: function(o){ + // summary: + // Stub function for use by specific plots. + // o: Object + // An object intended to represent event parameters. + var runName = o.id ? o.id : "default", a; + if (runName in this.animations) { + a = this.animations[runName]; + a.anim && a.anim.stop(true); + } else { + a = this.animations[runName] = {}; + } + if(o.element == "spider_poly"){ + if(!a.color){ + var color = o.shape.getFill(); + if(!color || !(color instanceof Color)){ + return; + } + a.color = { + start: color, + end: transColor(color) + }; + } + var start = a.color.start, end = a.color.end; + if(o.type == "onmouseout"){ + // swap colors + var t = start; start = end; end = t; + } + a.anim = gfxfx.animateFill({ + shape: o.shape, + duration: 800, + easing: easing.backOut, + color: {start: start, end: end} + }); + a.anim.play(); + }else if(o.element == "spider_circle"){ + var init, scale, defaultScale = 1.5; + if(o.type == "onmouseover"){ + init = m.identity; + scale = defaultScale; + //show tooltip + var aroundRect = {type: "rect"}; + aroundRect.x = o.cx; + aroundRect.y = o.cy; + aroundRect.width = aroundRect.height = 1; + var lt = html.coords(this.chart.node, true); + aroundRect.x += lt.x; + aroundRect.y += lt.y; + aroundRect.x = Math.round(aroundRect.x); + aroundRect.y = Math.round(aroundRect.y); + aroundRect.width = Math.ceil(aroundRect.width); + aroundRect.height = Math.ceil(aroundRect.height); + this.aroundRect = aroundRect; + var position = ["after", "before"]; + dc.doIfLoaded("dijit/Tooltip", dojo.hitch(this, function(Tooltip){ + Tooltip.show(o.tdata.sname + "<br/>" + o.tdata.key + "<br/>" + o.tdata.data, this.aroundRect, position); + })); + }else{ + init = m.scaleAt(defaultScale, o.cx, o.cy); + scale = 1/defaultScale; + dc.doIfLoaded("dijit/Tooltip", dojo.hitch(this, function(Tooltip){ + this.aroundRect && Tooltip.hide(this.aroundRect); + })); + } + var cs = o.shape.getShape(), + init = m.scaleAt(defaultScale, cs.cx, cs.cy), + kwArgs = { + shape: o.shape, + duration: 200, + easing: easing.backOut, + transform: [ + {name: "scaleAt", start: [1, cs.cx, cs.cy], end: [scale, cs.cx, cs.cy]}, + init + ] + }; + a.anim = gfxfx.animateTransform(kwArgs); + a.anim.play(); + }else if(o.element == "spider_plot"){ + //dojo gfx function "moveToFront" not work in IE + if (o.type == "onmouseover" && !has("ie")) { + o.shape.moveToFront(); + } + } + }, + _getBoundary: function(points){ + var xmax = points[0].x, + xmin = points[0].x, + ymax = points[0].y, + ymin = points[0].y; + for(var i = 0; i < points.length; i++){ + var point = points[i]; + xmax = Math.max(point.x, xmax); + ymax = Math.max(point.y, ymax); + xmin = Math.min(point.x, xmin); + ymin = Math.min(point.y, ymin); + } + return { + x: xmin, + y: ymin, + width: xmax - xmin, + height: ymax - ymin + }; + }, + + _drawArrow: function(s, start, end, stroke){ + var len = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)), + sin = (end.y - start.y)/len, cos = (end.x - start.x)/len, + point2 = {x: end.x + (len/3)*(-sin), y: end.y + (len/3)*cos}, + point3 = {x: end.x + (len/3)*sin, y: end.y + (len/3)*(-cos)}; + s.createPolyline([start, point2, point3]).setFill(stroke.color).setStroke(stroke); + }, + + _buildPoints: function(points, count, circle, radius, angle, recursive){ + for (var i = 0; i < count; i++) { + var end = angle + 2 * Math.PI * i / count; + points.push(this._getCoordinate(circle, radius, end)); + } + if(recursive){ + points.push(this._getCoordinate(circle, radius, angle + 2 * Math.PI)); + } + }, + + _getCoordinate: function(circle, radius, angle){ + return { + x: circle.cx + radius * Math.cos(angle), + y: circle.cy + radius * Math.sin(angle) + } + }, + + _getObjectLength: function(obj){ + var count = 0; + if(lang.isObject(obj)){ + for(var key in obj){ + count++; + } + } + return count; + }, + + // utilities + _getLabel: function(number){ + return dc.getLabel(number, this.opt.fixed, this.opt.precision); + } + }); + + function transColor(color){ + var a = new dxcolor.Color(color), + x = a.toHsl(); + if(x.s == 0){ + x.l = x.l < 50 ? 100 : 0; + }else{ + x.s = 100; + if(x.l < 50){ + x.l = 75; + }else if(x.l > 75){ + x.l = 50; + }else{ + x.l = x.l - 50 > 75 - x.l ? + 50 : 75; + } + } + var color = dxcolor.fromHsl(x); + color.a = 0.7; + return color; + } + + return Spider; // dojox.plot2d.Spider +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/Stacked.js b/js/dojo-1.7.2/dojox/charting/plot2d/Stacked.js new file mode 100644 index 0000000..9a39f6b --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/Stacked.js @@ -0,0 +1,197 @@ +//>>built +define("dojox/charting/plot2d/Stacked", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "./Default", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/functional/sequence"], + function(lang, declare, arr, Default, dc, df, dfr, dfs){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Stacked", Default, { + // summary: + // Like the default plot, Stacked sets up lines, areas and markers + // in a stacked fashion (values on the y axis added to each other) + // as opposed to a direct one. + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectStackedStats(this.series); + this._maxRunLength = stats.hmax; + return stats; + }, + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Stacked + // A reference to this plot for functional chaining. + if(this._maxRunLength <= 0){ + return this; + } + + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + } + // draw runs in backwards + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + + var t = this.chart.theme, events = this.events(), + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler); + + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next(this.opt.areas ? "area" : "line", [this.opt, run], true), + s = run.group, outline, + lpoly = arr.map(acc, function(v, i){ + return { + x: ht(i + 1) + offsets.l, + y: dim.height - offsets.b - vt(v) + }; + }, this); + + var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : ""; + + if(this.opt.areas){ + var apoly = lang.clone(lpoly); + if(this.opt.tension){ + var p=dc.curve(apoly, this.opt.tension); + p += " L" + lpoly[lpoly.length - 1].x + "," + (dim.height - offsets.b) + + " L" + lpoly[0].x + "," + (dim.height - offsets.b) + + " L" + lpoly[0].x + "," + lpoly[0].y; + run.dyn.fill = s.createPath(p).setFill(theme.series.fill).getFill(); + } else { + apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); + apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); + apoly.push(lpoly[0]); + run.dyn.fill = s.createPolyline(apoly).setFill(theme.series.fill).getFill(); + } + } + if(this.opt.lines || this.opt.markers){ + if(theme.series.outline){ + outline = dc.makeStroke(theme.series.outline); + outline.width = 2 * outline.width + theme.series.stroke.width; + } + } + if(this.opt.markers){ + run.dyn.marker = theme.symbol; + } + var frontMarkers, outlineMarkers, shadowMarkers; + if(theme.series.shadow && theme.series.stroke){ + var shadow = theme.series.shadow, + spoly = arr.map(lpoly, function(c){ + return {x: c.x + shadow.dx, y: c.y + shadow.dy}; + }); + if(this.opt.lines){ + if(this.opt.tension){ + run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadow).getStroke(); + } else { + run.dyn.shadow = s.createPolyline(spoly).setStroke(shadow).getStroke(); + } + } + if(this.opt.markers){ + shadow = theme.marker.shadow; + shadowMarkers = arr.map(spoly, function(c){ + return s.createPath("M" + c.x + " " + c.y + " " + theme.symbol). + setStroke(shadow).setFill(shadow.color); + }, this); + } + } + if(this.opt.lines){ + if(outline){ + if(this.opt.tension){ + run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke(); + } else { + run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke(); + } + } + if(this.opt.tension){ + run.dyn.stroke = s.createPath(lpath).setStroke(theme.series.stroke).getStroke(); + } else { + run.dyn.stroke = s.createPolyline(lpoly).setStroke(theme.series.stroke).getStroke(); + } + } + if(this.opt.markers){ + frontMarkers = new Array(lpoly.length); + outlineMarkers = new Array(lpoly.length); + outline = null; + if(theme.marker.outline){ + outline = dc.makeStroke(theme.marker.outline); + outline.width = 2 * outline.width + (theme.marker.stroke ? theme.marker.stroke.width : 0); + } + arr.forEach(lpoly, function(c, i){ + var path = "M" + c.x + " " + c.y + " " + theme.symbol; + if(outline){ + outlineMarkers[i] = s.createPath(path).setStroke(outline); + } + frontMarkers[i] = s.createPath(path).setStroke(theme.marker.stroke).setFill(theme.marker.fill); + }, this); + if(events){ + var eventSeries = new Array(frontMarkers.length); + arr.forEach(frontMarkers, function(s, i){ + var o = { + element: "marker", + index: i, + run: run, + shape: s, + outline: outlineMarkers[i] || null, + shadow: shadowMarkers && shadowMarkers[i] || null, + cx: lpoly[i].x, + cy: lpoly[i].y, + x: i + 1, + y: run.data[i] + }; + this._connectEvents(o); + eventSeries[i] = o; + }, this); + this._eventSeries[run.name] = eventSeries; + }else{ + delete this._eventSeries[run.name]; + } + } + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + } + this.dirty = false; + return this; // dojox.charting.plot2d.Stacked + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/StackedAreas.js b/js/dojo-1.7.2/dojox/charting/plot2d/StackedAreas.js new file mode 100644 index 0000000..2bc3f6b --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/StackedAreas.js @@ -0,0 +1,17 @@ +//>>built +define("dojox/charting/plot2d/StackedAreas", ["dojo/_base/declare", "./Stacked"], function(declare, Stacked){ +/*===== +var Stacked = dojox.charting.plot2d.Stacked; +=====*/ + return declare("dojox.charting.plot2d.StackedAreas", Stacked, { + // summary: + // A convenience object to set up a stacked area plot. + constructor: function(){ + // summary: + // Force our Stacked plotter to include both lines and areas. + this.opt.lines = true; + this.opt.areas = true; + } + }); +}); + diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/StackedBars.js b/js/dojo-1.7.2/dojox/charting/plot2d/StackedBars.js new file mode 100644 index 0000000..3019c90 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/StackedBars.js @@ -0,0 +1,135 @@ +//>>built +define("dojox/charting/plot2d/StackedBars", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Bars", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/functional/sequence"], + function(lang, arr, declare, Bars, dc, df, dfr, dfs){ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); +/*===== +var bars = dojox.charting.plot2d.Bars; +=====*/ + return declare("dojox.charting.plot2d.StackedBars", Bars, { + // summary: + // The plot object representing a stacked bar chart (horizontal bars). + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectStackedStats(this.series), t; + this._maxRunLength = stats.hmax; + stats.hmin -= 0.5; + stats.hmax += 0.5; + t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; + t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; + return stats; + }, + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.StackedBars + // A reference to this plot for functional chaining. + if(this._maxRunLength <= 0){ + return this; + } + + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + } + // draw runs in backwards + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, height, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + events = this.events(); + f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt); + gap = f.gap; + height = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("bar", [this.opt, run]), s = run.group, + eventSeries = new Array(acc.length); + for(var j = 0; j < acc.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = acc[j], + width = ht(v), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "bar", value, true) : + t.post(theme, "bar"); + if(width >= 0 && height >= 1){ + var rect = { + x: offsets.l, + y: dim.height - offsets.b - vt(j + 1.5) + gap, + width: width, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "bar", + index: j, + run: run, + shape: shape, + x: v, + y: j + 1.5 + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateBar(shape, offsets.l, -width); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + } + this.dirty = false; + return this; // dojox.charting.plot2d.StackedBars + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/StackedColumns.js b/js/dojo-1.7.2/dojox/charting/plot2d/StackedColumns.js new file mode 100644 index 0000000..4f21e31 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/StackedColumns.js @@ -0,0 +1,133 @@ +//>>built +define("dojox/charting/plot2d/StackedColumns", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Columns", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/functional/sequence"], + function(lang, arr, declare, Columns, dc, df, dfr, dfs){ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); +/*===== +var Columns = dojox.charting.plot2d.Columns; +=====*/ + return declare("dojox.charting.plot2d.StackedColumns", Columns, { + // summary: + // The plot object representing a stacked column chart (vertical bars). + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectStackedStats(this.series); + this._maxRunLength = stats.hmax; + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.StackedColumns + // A reference to this plot for functional chaining. + if(this._maxRunLength <= 0){ + return this; + } + + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + } + // draw runs in backwards + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("column", [this.opt, run]), s = run.group, + eventSeries = new Array(acc.length); + for(var j = 0; j < acc.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = acc[j], + height = vt(v), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "column", value, true) : + t.post(theme, "column"); + if(width >= 1 && height >= 0){ + var rect = { + x: offsets.l + ht(j + 0.5) + gap, + y: dim.height - offsets.b - vt(v), + width: width, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "column", + index: j, + run: run, + shape: shape, + x: j + 0.5, + y: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateColumn(shape, dim.height - offsets.b, height); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + } + this.dirty = false; + return this; // dojox.charting.plot2d.StackedColumns + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/StackedLines.js b/js/dojo-1.7.2/dojox/charting/plot2d/StackedLines.js new file mode 100644 index 0000000..9751d85 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/StackedLines.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/plot2d/StackedLines", ["dojo/_base/declare", "./Stacked"], function(declare, Stacked){ +/*===== +var Stacked = dojox.charting.plot2d.Stacked; +=====*/ + return declare("dojox.charting.plot2d.StackedLines", Stacked, { + // summary: + // A convenience object to create a stacked line chart. + constructor: function(){ + // summary: + // Force our Stacked base to be lines only. + this.opt.lines = true; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/_PlotEvents.js b/js/dojo-1.7.2/dojox/charting/plot2d/_PlotEvents.js new file mode 100644 index 0000000..c01a28b --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/_PlotEvents.js @@ -0,0 +1,121 @@ +//>>built +define("dojox/charting/plot2d/_PlotEvents", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/_base/connect"], + function(lang, arr, declare, hub){ + + return declare("dojox.charting.plot2d._PlotEvents", null, { + constructor: function(){ + this._shapeEvents = []; + this._eventSeries = {}; + }, + destroy: function(){ + // summary: + // Destroy any internal elements and event handlers. + this.resetEvents(); + this.inherited(arguments); + }, + plotEvent: function(o){ + // summary: + // Stub function for use by specific plots. + // o: Object + // An object intended to represent event parameters. + }, + raiseEvent: function(o){ + // summary: + // Raises events in predefined order + // o: Object + // An object intended to represent event parameters. + this.plotEvent(o); + var t = lang.delegate(o); + t.originalEvent = o.type; + t.originalPlot = o.plot; + t.type = "onindirect"; + arr.forEach(this.chart.stack, function(plot){ + if(plot !== this && plot.plotEvent){ + t.plot = plot; + plot.plotEvent(t); + } + }, this); + }, + connect: function(object, method){ + // summary: + // Helper function to connect any object's method to our plotEvent. + // object: Object + // The object to connect to. + // method: String|Function + // The method to fire when our plotEvent is fired. + // returns: Array + // The handle as returned from dojo.connect (see dojo.connect). + this.dirty = true; + return hub.connect(this, "plotEvent", object, method); // Array + }, + events: function(){ + // summary: + // Find out if any event handlers have been connected to our plotEvent. + // returns: Boolean + // A flag indicating that there are handlers attached. + return !!this.plotEvent.after; + }, + resetEvents: function(){ + // summary: + // Reset all events attached to our plotEvent (i.e. disconnect). + if(this._shapeEvents.length){ + arr.forEach(this._shapeEvents, function(item){ + item.shape.disconnect(item.handle); + }); + this._shapeEvents = []; + } + this.raiseEvent({type: "onplotreset", plot: this}); + }, + _connectSingleEvent: function(o, eventName){ + this._shapeEvents.push({ + shape: o.eventMask, + handle: o.eventMask.connect(eventName, this, function(e){ + o.type = eventName; + o.event = e; + this.raiseEvent(o); + o.event = null; + }) + }); + }, + _connectEvents: function(o){ + if(o){ + o.chart = this.chart; + o.plot = this; + o.hAxis = this.hAxis || null; + o.vAxis = this.vAxis || null; + o.eventMask = o.eventMask || o.shape; + this._connectSingleEvent(o, "onmouseover"); + this._connectSingleEvent(o, "onmouseout"); + this._connectSingleEvent(o, "onclick"); + } + }, + _reconnectEvents: function(seriesName){ + var a = this._eventSeries[seriesName]; + if(a){ + arr.forEach(a, this._connectEvents, this); + } + }, + fireEvent: function(seriesName, eventName, index, eventObject){ + // summary: + // Emulates firing an event for a given data value (specified by + // an index) of a given series. + // seriesName: String: + // Series name. + // eventName: String: + // Event name to emulate. + // index: Number: + // Valid data value index used to raise an event. + // eventObject: Object?: + // Optional event object. Especially useful for synthetic events. + // Default: null. + var s = this._eventSeries[seriesName]; + if(s && s.length && index < s.length){ + var o = s[index]; + o.type = eventName; + o.event = eventObject || null; + this.raiseEvent(o); + o.event = null; + } + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot2d/common.js b/js/dojo-1.7.2/dojox/charting/plot2d/common.js new file mode 100644 index 0000000..441ca7a --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot2d/common.js @@ -0,0 +1,217 @@ +//>>built +define("dojox/charting/plot2d/common", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/Color", + "dojox/gfx", "dojox/lang/functional", "../scaler/common"], + function(lang, arr, Color, g, df, sc){ + + var common = lang.getObject("dojox.charting.plot2d.common", true); + + return lang.mixin(common, { + doIfLoaded: sc.doIfLoaded, + makeStroke: function(stroke){ + if(!stroke){ return stroke; } + if(typeof stroke == "string" || stroke instanceof Color){ + stroke = {color: stroke}; + } + return g.makeParameters(g.defaultStroke, stroke); + }, + augmentColor: function(target, color){ + var t = new Color(target), + c = new Color(color); + c.a = t.a; + return c; + }, + augmentStroke: function(stroke, color){ + var s = common.makeStroke(stroke); + if(s){ + s.color = common.augmentColor(s.color, color); + } + return s; + }, + augmentFill: function(fill, color){ + var fc, c = new Color(color); + if(typeof fill == "string" || fill instanceof Color){ + return common.augmentColor(fill, color); + } + return fill; + }, + + defaultStats: { + vmin: Number.POSITIVE_INFINITY, vmax: Number.NEGATIVE_INFINITY, + hmin: Number.POSITIVE_INFINITY, hmax: Number.NEGATIVE_INFINITY + }, + + collectSimpleStats: function(series){ + var stats = lang.delegate(common.defaultStats); + for(var i = 0; i < series.length; ++i){ + var run = series[i]; + for(var j = 0; j < run.data.length; j++){ + if(run.data[j] !== null){ + if(typeof run.data[j] == "number"){ + // 1D case + var old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, i){ + if(val !== null){ + var x = i + 1, y = val; + if(isNaN(y)){ y = 0; } + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, y); + stats.vmax = Math.max(stats.vmax, y); + } + }); + } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + }else{ + // 2D case + var old_hmin = stats.hmin, old_hmax = stats.hmax, + old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("xmin" in run) || !("xmax" in run) || !("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, i){ + if(val !== null){ + var x = "x" in val ? val.x : i + 1, y = val.y; + if(isNaN(x)){ x = 0; } + if(isNaN(y)){ y = 0; } + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, y); + stats.vmax = Math.max(stats.vmax, y); + } + }); + } + if("xmin" in run){ stats.hmin = Math.min(old_hmin, run.xmin); } + if("xmax" in run){ stats.hmax = Math.max(old_hmax, run.xmax); } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + } + + break; + } + } + } + return stats; + }, + + calculateBarSize: function(/* Number */ availableSize, /* Object */ opt, /* Number? */ clusterSize){ + if(!clusterSize){ + clusterSize = 1; + } + var gap = opt.gap, size = (availableSize - 2 * gap) / clusterSize; + if("minBarSize" in opt){ + size = Math.max(size, opt.minBarSize); + } + if("maxBarSize" in opt){ + size = Math.min(size, opt.maxBarSize); + } + size = Math.max(size, 1); + gap = (availableSize - size * clusterSize) / 2; + return {size: size, gap: gap}; // Object + }, + + collectStackedStats: function(series){ + // collect statistics + var stats = lang.clone(common.defaultStats); + if(series.length){ + // 1st pass: find the maximal length of runs + stats.hmin = Math.min(stats.hmin, 1); + stats.hmax = df.foldl(series, "seed, run -> Math.max(seed, run.data.length)", stats.hmax); + // 2nd pass: stack values + for(var i = 0; i < stats.hmax; ++i){ + var v = series[0].data[i]; + v = v && (typeof v == "number" ? v : v.y); + if(isNaN(v)){ v = 0; } + stats.vmin = Math.min(stats.vmin, v); + for(var j = 1; j < series.length; ++j){ + var t = series[j].data[i]; + t = t && (typeof t == "number" ? t : t.y); + if(isNaN(t)){ t = 0; } + v += t; + } + stats.vmax = Math.max(stats.vmax, v); + } + } + return stats; + }, + + curve: function(/* Number[] */a, /* Number|String */tension){ + // FIX for #7235, submitted by Enzo Michelangeli. + // Emulates the smoothing algorithms used in a famous, unnamed spreadsheet + // program ;) + var array = a.slice(0); + if(tension == "x") { + array[array.length] = arr[0]; // add a last element equal to the first, closing the loop + } + var p=arr.map(array, function(item, i){ + if(i==0){ return "M" + item.x + "," + item.y; } + if(!isNaN(tension)) { // use standard Dojo smoothing in tension is numeric + var dx=item.x-array[i-1].x, dy=array[i-1].y; + return "C"+(item.x-(tension-1)*(dx/tension))+","+dy+" "+(item.x-(dx/tension))+","+item.y+" "+item.x+","+item.y; + } else if(tension == "X" || tension == "x" || tension == "S") { + // use Excel "line smoothing" algorithm (http://xlrotor.com/resources/files.shtml) + var p0, p1 = array[i-1], p2 = array[i], p3; + var bz1x, bz1y, bz2x, bz2y; + var f = 1/6; + if(i==1) { + if(tension == "x") { + p0 = array[array.length-2]; + } else { // "tension == X || tension == "S" + p0 = p1; + } + f = 1/3; + } else { + p0 = array[i-2]; + } + if(i==(array.length-1)) { + if(tension == "x") { + p3 = array[1]; + } else { // "tension == X || tension == "S" + p3 = p2; + } + f = 1/3; + } else { + p3 = array[i+1]; + } + var p1p2 = Math.sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); + var p0p2 = Math.sqrt((p2.x-p0.x)*(p2.x-p0.x)+(p2.y-p0.y)*(p2.y-p0.y)); + var p1p3 = Math.sqrt((p3.x-p1.x)*(p3.x-p1.x)+(p3.y-p1.y)*(p3.y-p1.y)); + + var p0p2f = p0p2 * f; + var p1p3f = p1p3 * f; + + if(p0p2f > p1p2/2 && p1p3f > p1p2/2) { + p0p2f = p1p2/2; + p1p3f = p1p2/2; + } else if(p0p2f > p1p2/2) { + p0p2f = p1p2/2; + p1p3f = p1p2/2 * p1p3/p0p2; + } else if(p1p3f > p1p2/2) { + p1p3f = p1p2/2; + p0p2f = p1p2/2 * p0p2/p1p3; + } + + if(tension == "S") { + if(p0 == p1) { p0p2f = 0; } + if(p2 == p3) { p1p3f = 0; } + } + + bz1x = p1.x + p0p2f*(p2.x - p0.x)/p0p2; + bz1y = p1.y + p0p2f*(p2.y - p0.y)/p0p2; + bz2x = p2.x - p1p3f*(p3.x - p1.x)/p1p3; + bz2y = p2.y - p1p3f*(p3.y - p1.y)/p1p3; + } + return "C"+(bz1x+","+bz1y+" "+bz2x+","+bz2y+" "+p2.x+","+p2.y); + }); + return p.join(" "); + }, + + getLabel: function(/*Number*/number, /*Boolean*/fixed, /*Number*/precision){ + return sc.doIfLoaded("dojo/number", function(numberLib){ + return (fixed ? numberLib.format(number, {places : precision}) : + numberLib.format(number)) || ""; + }, function(){ + return fixed ? number.toFixed(precision) : number.toString(); + }); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot3d/Bars.js b/js/dojo-1.7.2/dojox/charting/plot3d/Bars.js new file mode 100644 index 0000000..9937efe --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot3d/Bars.js @@ -0,0 +1,62 @@ +//>>built +define("dojox/charting/plot3d/Bars", ["dojox/gfx3d", "dojo/_base/window", "dojo/_base/declare", "dojo/_base/Color", "./Base"], + function(gfx3d, win, declare, Color, Base) { + + // reduce function borrowed from dojox.fun + var reduce = function(/*Array*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns the final value. + a = typeof a == "string" ? a.split("") : a; o = o || win.global; + var z = a[0]; + for(var i = 1; i < a.length; z = f.call(o, z, a[i++])); + return z; // Object + }; + /*===== + var Base = dojox.charting.plot3d.Base; + =====*/ + return declare("dojox.charting.plot3d.Bars", Base, { + constructor: function(width, height, kwArgs){ + this.depth = "auto"; + this.gap = 0; + this.data = []; + this.material = {type: "plastic", finish: "dull", color: "lime"}; + if(kwArgs){ + if("depth" in kwArgs){ this.depth = kwArgs.depth; } + if("gap" in kwArgs){ this.gap = kwArgs.gap; } + if("material" in kwArgs){ + var m = kwArgs.material; + if(typeof m == "string" || m instanceof Color){ + this.material.color = m; + }else{ + this.material = m; + } + } + } + }, + getDepth: function(){ + if(this.depth == "auto"){ + var w = this.width; + if(this.data && this.data.length){ + w = w / this.data.length; + } + return w - 2 * this.gap; + } + return this.depth; + }, + generate: function(chart, creator){ + if(!this.data){ return this; } + var step = this.width / this.data.length, org = 0, + depth = this.depth == "auto" ? step - 2 * this.gap : this.depth, + scale = this.height / reduce(this.data, Math.max); + if(!creator){ creator = chart.view; } + for(var i = 0; i < this.data.length; ++i, org += step){ + creator + .createCube({ + bottom: {x: org + this.gap, y: 0, z: 0}, + top: {x: org + step - this.gap, y: this.data[i] * scale, z: depth} + }) + .setFill(this.material); + } + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/plot3d/Base.js b/js/dojo-1.7.2/dojox/charting/plot3d/Base.js new file mode 100644 index 0000000..7929ae9 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot3d/Base.js @@ -0,0 +1,20 @@ +//>>built +define("dojox/charting/plot3d/Base", ["dojo/_base/declare"], + function(declare) { + return declare("dojox.charting.plot3d.Base", null, { + constructor: function(width, height, kwArgs){ + this.width = width; + this.height = height; + }, + setData: function(data){ + this.data = data ? data : []; + return this; + }, + getDepth: function(){ + return this.depth; + }, + generate: function(chart, creator){ + } + }); +}); + diff --git a/js/dojo-1.7.2/dojox/charting/plot3d/Cylinders.js b/js/dojo-1.7.2/dojox/charting/plot3d/Cylinders.js new file mode 100644 index 0000000..d9e8be4 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/plot3d/Cylinders.js @@ -0,0 +1,66 @@ +//>>built +define("dojox/charting/plot3d/Cylinders", ["dojox/gfx3d", "dojox/gfx3d/matrix", "dojo/_base/declare", "dojo/_base/Color", "dojo/_base/window", "./Base"], + function(gfx3d, matrix3d, declare, Color, win, Base) { + + // reduce function borrowed from dojox.fun + var reduce = function(/*Array*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns the final value. + a = typeof a == "string" ? a.split("") : a; o = o || win.global; + var z = a[0]; + for(var i = 1; i < a.length; z = f.call(o, z, a[i++])); + return z; // Object + }; + /*===== + var Base = dojox.charting.plot3d.Base; + =====*/ + return declare("dojox.charting.plot3d.Cylinders", Base, { + constructor: function(width, height, kwArgs){ + this.depth = "auto"; + this.gap = 0; + this.data = []; + this.material = {type: "plastic", finish: "shiny", color: "lime"}; + this.outline = null; + if(kwArgs){ + if("depth" in kwArgs){ this.depth = kwArgs.depth; } + if("gap" in kwArgs){ this.gap = kwArgs.gap; } + if("material" in kwArgs){ + var m = kwArgs.material; + if(typeof m == "string" || m instanceof Color){ + this.material.color = m; + }else{ + this.material = m; + } + } + if("outline" in kwArgs){ this.outline = kwArgs.outline; } + } + }, + getDepth: function(){ + if(this.depth == "auto"){ + var w = this.width; + if(this.data && this.data.length){ + w = w / this.data.length; + } + return w - 2 * this.gap; + } + return this.depth; + }, + generate: function(chart, creator){ + if(!this.data){ return this; } + var step = this.width / this.data.length, org = 0, + scale = this.height / reduce(this.data, Math.max); + if(!creator){ creator = chart.view; } + for(var i = 0; i < this.data.length; ++i, org += step){ + creator + .createCylinder({ + center: {x: org + step / 2, y: 0, z: 0}, + radius: step / 2 - this.gap, + height: this.data[i] * scale + }) + .setTransform(matrix3d.rotateXg(-90)) + .setFill(this.material).setStroke(this.outline); + } + } + }); +}); + diff --git a/js/dojo-1.7.2/dojox/charting/resources/Legend.css b/js/dojo-1.7.2/dojox/charting/resources/Legend.css new file mode 100644 index 0000000..3eae82d --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/resources/Legend.css @@ -0,0 +1,24 @@ +.dojoxLegendNode { + background-color:#F7F7F7; + border:1px solid #CCCCCC; + margin:0; + padding:0; +} +.dojoxLegendNode td{ + padding: 6px 4px 6px 6px; +} +.dojoxLegendIcon { + padding: 0px; + margin: 0 2px 0 4px; +} +.dojoxLegendIcon div{ + float: left; +} +.dj_ie .dojoxLegendNode td{ + padding: 5px; +} +.dj_ie .dojoxLegendIcon { + padding: 0px; + margin: 0 2px 0 5px; + vertical-align: middle; +} diff --git a/js/dojo-1.7.2/dojox/charting/scaler/common.js b/js/dojo-1.7.2/dojox/charting/scaler/common.js new file mode 100644 index 0000000..9bc62bd --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/scaler/common.js @@ -0,0 +1,76 @@ +//>>built +define("dojox/charting/scaler/common", ["dojo/_base/lang"], function(lang){ + + var eq = function(/*Number*/ a, /*Number*/ b){ + // summary: compare two FP numbers for equality + return Math.abs(a - b) <= 1e-6 * (Math.abs(a) + Math.abs(b)); // Boolean + }; + + var common = lang.getObject("dojox.charting.scaler.common", true); + + var testedModules = {}; + + return lang.mixin(common, { + doIfLoaded: function(moduleName, ifloaded, ifnotloaded){ + if(testedModules[moduleName] == undefined){ + try{ + testedModules[moduleName] = require(moduleName); + }catch(e){ + testedModules[moduleName] = null; + } + } + if(testedModules[moduleName]){ + return ifloaded(testedModules[moduleName]); + }else{ + return ifnotloaded(); + } + }, + findString: function(/*String*/ val, /*Array*/ text){ + val = val.toLowerCase(); + for(var i = 0; i < text.length; ++i){ + if(val == text[i]){ return true; } + } + return false; + }, + getNumericLabel: function(/*Number*/ number, /*Number*/ precision, /*Object*/ kwArgs){ + var def = ""; + common.doIfLoaded("dojo/number", function(numberLib){ + def = (kwArgs.fixed ? numberLib.format(number, {places : precision < 0 ? -precision : 0}) : + numberLib.format(number)) || ""; + }, function(){ + def = kwArgs.fixed ? number.toFixed(precision < 0 ? -precision : 0) : number.toString(); + }); + if(kwArgs.labelFunc){ + var r = kwArgs.labelFunc(def, number, precision); + if(r){ return r; } + // else fall through to the regular labels search + } + if(kwArgs.labels){ + // classic binary search + var l = kwArgs.labels, lo = 0, hi = l.length; + while(lo < hi){ + var mid = Math.floor((lo + hi) / 2), val = l[mid].value; + if(val < number){ + lo = mid + 1; + }else{ + hi = mid; + } + } + // lets take into account FP errors + if(lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + --lo; + if(lo >= 0 && lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + lo += 2; + if(lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + // otherwise we will produce a number + } + return def; + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/scaler/linear.js b/js/dojo-1.7.2/dojox/charting/scaler/linear.js new file mode 100644 index 0000000..3f4c8eb --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/scaler/linear.js @@ -0,0 +1,251 @@ +//>>built +define("dojox/charting/scaler/linear", ["dojo/_base/lang", "./common"], + function(lang, common){ + var linear = lang.getObject("dojox.charting.scaler.linear", true); + + var deltaLimit = 3, // pixels + findString = common.findString, + getLabel = common.getNumericLabel; + + var calcTicks = function(min, max, kwArgs, majorTick, minorTick, microTick, span){ + kwArgs = lang.delegate(kwArgs); + if(!majorTick){ + if(kwArgs.fixUpper == "major"){ kwArgs.fixUpper = "minor"; } + if(kwArgs.fixLower == "major"){ kwArgs.fixLower = "minor"; } + } + if(!minorTick){ + if(kwArgs.fixUpper == "minor"){ kwArgs.fixUpper = "micro"; } + if(kwArgs.fixLower == "minor"){ kwArgs.fixLower = "micro"; } + } + if(!microTick){ + if(kwArgs.fixUpper == "micro"){ kwArgs.fixUpper = "none"; } + if(kwArgs.fixLower == "micro"){ kwArgs.fixLower = "none"; } + } + var lowerBound = findString(kwArgs.fixLower, ["major"]) ? + Math.floor(kwArgs.min / majorTick) * majorTick : + findString(kwArgs.fixLower, ["minor"]) ? + Math.floor(kwArgs.min / minorTick) * minorTick : + findString(kwArgs.fixLower, ["micro"]) ? + Math.floor(kwArgs.min / microTick) * microTick : kwArgs.min, + upperBound = findString(kwArgs.fixUpper, ["major"]) ? + Math.ceil(kwArgs.max / majorTick) * majorTick : + findString(kwArgs.fixUpper, ["minor"]) ? + Math.ceil(kwArgs.max / minorTick) * minorTick : + findString(kwArgs.fixUpper, ["micro"]) ? + Math.ceil(kwArgs.max / microTick) * microTick : kwArgs.max; + + if(kwArgs.useMin){ min = lowerBound; } + if(kwArgs.useMax){ max = upperBound; } + + var majorStart = (!majorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major"])) ? + min : Math.ceil(min / majorTick) * majorTick, + minorStart = (!minorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor"])) ? + min : Math.ceil(min / minorTick) * minorTick, + microStart = (! microTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor", "micro"])) ? + min : Math.ceil(min / microTick) * microTick, + majorCount = !majorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major"]) ? + Math.round((max - majorStart) / majorTick) : + Math.floor((max - majorStart) / majorTick)) + 1, + minorCount = !minorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor"]) ? + Math.round((max - minorStart) / minorTick) : + Math.floor((max - minorStart) / minorTick)) + 1, + microCount = !microTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor", "micro"]) ? + Math.round((max - microStart) / microTick) : + Math.floor((max - microStart) / microTick)) + 1, + minorPerMajor = minorTick ? Math.round(majorTick / minorTick) : 0, + microPerMinor = microTick ? Math.round(minorTick / microTick) : 0, + majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0, + minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0, + scale = span / (max - min); + if(!isFinite(scale)){ scale = 1; } + + return { + bounds: { + lower: lowerBound, + upper: upperBound, + from: min, + to: max, + scale: scale, + span: span + }, + major: { + tick: majorTick, + start: majorStart, + count: majorCount, + prec: majorPrecision + }, + minor: { + tick: minorTick, + start: minorStart, + count: minorCount, + prec: minorPrecision + }, + micro: { + tick: microTick, + start: microStart, + count: microCount, + prec: 0 + }, + minorPerMajor: minorPerMajor, + microPerMinor: microPerMinor, + scaler: linear + }; + }; + + return lang.mixin(linear, { + buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){ + var h = {fixUpper: "none", fixLower: "none", natural: false}; + if(kwArgs){ + if("fixUpper" in kwArgs){ h.fixUpper = String(kwArgs.fixUpper); } + if("fixLower" in kwArgs){ h.fixLower = String(kwArgs.fixLower); } + if("natural" in kwArgs){ h.natural = Boolean(kwArgs.natural); } + } + + // update bounds + if("min" in kwArgs){ min = kwArgs.min; } + if("max" in kwArgs){ max = kwArgs.max; } + if(kwArgs.includeZero){ + if(min > 0){ min = 0; } + if(max < 0){ max = 0; } + } + h.min = min; + h.useMin = true; + h.max = max; + h.useMax = true; + + if("from" in kwArgs){ + min = kwArgs.from; + h.useMin = false; + } + if("to" in kwArgs){ + max = kwArgs.to; + h.useMax = false; + } + + // check for erroneous condition + if(max <= min){ + return calcTicks(min, max, h, 0, 0, 0, span); // Object + } + + var mag = Math.floor(Math.log(max - min) / Math.LN10), + major = kwArgs && ("majorTickStep" in kwArgs) ? kwArgs.majorTickStep : Math.pow(10, mag), + minor = 0, micro = 0, ticks; + + // calculate minor ticks + if(kwArgs && ("minorTickStep" in kwArgs)){ + minor = kwArgs.minorTickStep; + }else{ + do{ + minor = major / 10; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } + } + minor = major / 5; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } + } + minor = major / 2; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } + } + return calcTicks(min, max, h, major, 0, 0, span); // Object + }while(false); + } + + // calculate micro ticks + if(kwArgs && ("microTickStep" in kwArgs)){ + micro = kwArgs.microTickStep; + ticks = calcTicks(min, max, h, major, minor, micro, span); + }else{ + do{ + micro = minor / 10; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = minor / 5; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = minor / 2; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = 0; + }while(false); + } + + return micro ? ticks : calcTicks(min, max, h, major, minor, 0, span); // Object + }, + buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){ + var step, next, tick, + nextMajor = scaler.major.start, + nextMinor = scaler.minor.start, + nextMicro = scaler.micro.start; + if(kwArgs.microTicks && scaler.micro.tick){ + step = scaler.micro.tick, next = nextMicro; + }else if(kwArgs.minorTicks && scaler.minor.tick){ + step = scaler.minor.tick, next = nextMinor; + }else if(scaler.major.tick){ + step = scaler.major.tick, next = nextMajor; + }else{ + // no ticks + return null; + } + // make sure that we have finite bounds + var revScale = 1 / scaler.bounds.scale; + if(scaler.bounds.to <= scaler.bounds.from || isNaN(revScale) || !isFinite(revScale) || + step <= 0 || isNaN(step) || !isFinite(step)){ + // no ticks + return null; + } + // loop over all ticks + var majorTicks = [], minorTicks = [], microTicks = []; + while(next <= scaler.bounds.to + revScale){ + if(Math.abs(nextMajor - next) < step / 2){ + // major tick + tick = {value: nextMajor}; + if(kwArgs.majorLabels){ + tick.label = getLabel(nextMajor, scaler.major.prec, kwArgs); + } + majorTicks.push(tick); + nextMajor += scaler.major.tick; + nextMinor += scaler.minor.tick; + nextMicro += scaler.micro.tick; + }else if(Math.abs(nextMinor - next) < step / 2){ + // minor tick + if(kwArgs.minorTicks){ + tick = {value: nextMinor}; + if(kwArgs.minorLabels && (scaler.minMinorStep <= scaler.minor.tick * scaler.bounds.scale)){ + tick.label = getLabel(nextMinor, scaler.minor.prec, kwArgs); + } + minorTicks.push(tick); + } + nextMinor += scaler.minor.tick; + nextMicro += scaler.micro.tick; + }else{ + // micro tick + if(kwArgs.microTicks){ + microTicks.push({value: nextMicro}); + } + nextMicro += scaler.micro.tick; + } + next += step; + } + return {major: majorTicks, minor: minorTicks, micro: microTicks}; // Object + }, + getTransformerFromModel: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return (x - offset) * scale; }; // Function + }, + getTransformerFromPlot: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return x / scale + offset; }; // Function + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/scaler/primitive.js b/js/dojo-1.7.2/dojox/charting/scaler/primitive.js new file mode 100644 index 0000000..c96f58d --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/scaler/primitive.js @@ -0,0 +1,37 @@ +//>>built +define("dojox/charting/scaler/primitive", ["dojo/_base/lang"], + function(lang){ + var primitive = lang.getObject("dojox.charting.scaler.primitive", true); + return lang.mixin(primitive, { + buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){ + if(min == max){ + // artificially extend bounds + min -= 0.5; + max += 0.5; + // now the line will be centered + } + return { + bounds: { + lower: min, + upper: max, + from: min, + to: max, + scale: span / (max - min), + span: span + }, + scaler: primitive + }; + }, + buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){ + return {major: [], minor: [], micro: []}; // Object + }, + getTransformerFromModel: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return (x - offset) * scale; }; // Function + }, + getTransformerFromPlot: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return x / scale + offset; }; // Function + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Adobebricks.js b/js/dojo-1.7.2/dojox/charting/themes/Adobebricks.js new file mode 100644 index 0000000..1dd7e13 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Adobebricks.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/Adobebricks", ["../Theme", "./common"], function(Theme, themes){ + + themes.Adobebricks=new Theme({ + colors: [ + "#7f2518", + "#3e170c", + "#cc3927", + "#651f0e", + "#8c271c" + ] + }); + + return themes.Adobebricks; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Algae.js b/js/dojo-1.7.2/dojox/charting/themes/Algae.js new file mode 100644 index 0000000..68bd6bf --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Algae.js @@ -0,0 +1,13 @@ +//>>built +define("dojox/charting/themes/Algae", ["../Theme", "./common"], function(Theme, themes){ + themes.Algae = new Theme({ + colors: [ + "#57808f", + "#506885", + "#4f7878", + "#558f7f", + "#508567" + ] + }); + return themes.Algae; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Bahamation.js b/js/dojo-1.7.2/dojox/charting/themes/Bahamation.js new file mode 100644 index 0000000..7538902 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Bahamation.js @@ -0,0 +1,13 @@ +//>>built +define("dojox/charting/themes/Bahamation", ["../Theme", "./common"], function(Theme, themes){ + themes.Bahamation=new Theme({ + colors: [ + "#3f9998", + "#3fc0c3", + "#70c058", + "#ef446f", + "#c663a6" + ] + }); + return themes.Bahamation; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/BlueDusk.js b/js/dojo-1.7.2/dojox/charting/themes/BlueDusk.js new file mode 100644 index 0000000..71b8e7f --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/BlueDusk.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/BlueDusk", ["../Theme", "./common"], function(Theme, themes){ + + themes.BlueDusk=new Theme({ + colors: [ + "#292e76", + "#3e56a6", + "#10143f", + "#33449c", + "#798dcd" + ] + }); + + return themes.BlueDusk; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Charged.js b/js/dojo-1.7.2/dojox/charting/themes/Charged.js new file mode 100644 index 0000000..6610509 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Charged.js @@ -0,0 +1,88 @@ +//>>built +define("dojox/charting/themes/Charged", ["../Theme", "dojox/gfx/gradutils", "./common"], function(Theme, gradutils, themes){ + + var g = Theme.generateGradient, + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 75}; + + themes.Charged = new Theme({ + chart: { + fill: "#ededdf", + pageStyle: {backgroundColor: "#ededdf", backgroundImage: "none", color: "inherit"} + }, + plotarea: { + fill: "transparent" + }, + axis:{ + stroke: { // the axis itself + color: "#808078", + width: 1 + }, + tick: { // used as a foundation for all ticks + color: "#b3b3a8", + position: "center", + font: "normal normal normal 7pt Helvetica, Arial, sans-serif", // labels on axis + fontColor: "#808078" // color of labels + } + }, + series: { + stroke: {width: 2, color: "#595954"}, + outline: null, + font: "normal normal normal 8pt Helvetica, Arial, sans-serif", + fontColor: "#808078" + }, + marker: { + stroke: {width: 3, color: "#595954"}, + outline: null, + font: "normal normal normal 8pt Helvetica, Arial, sans-serif", + fontColor: "#808078" + }, + seriesThemes: [ + {fill: g(defaultFill, "#004cbf", "#06f")}, + {fill: g(defaultFill, "#bf004c", "#f06")}, + {fill: g(defaultFill, "#43bf00", "#6f0")}, + {fill: g(defaultFill, "#7300bf", "#90f")}, + {fill: g(defaultFill, "#bf7300", "#f90")}, + {fill: g(defaultFill, "#00bf73", "#0f9")} + ], + markerThemes: [ + {fill: "#06f", stroke: {color: "#06f"}}, + {fill: "#f06", stroke: {color: "#f06"}}, + {fill: "#6f0", stroke: {color: "#6f0"}}, + {fill: "#90f", stroke: {color: "#90f"}}, + {fill: "#f90", stroke: {color: "#f90"}}, + {fill: "#0f9", stroke: {color: "#0f9"}} + ] + }); + + themes.Charged.next = function(elementType, mixin, doPost){ + var isLine = elementType == "line"; + if(isLine || elementType == "area"){ + // custom processing for lines: substitute colors + var s = this.seriesThemes[this._current % this.seriesThemes.length]; + s.fill.space = "plot"; + if(isLine){ + s.stroke = { width: 2.5, color: s.fill.colors[1].color}; + } + if(elementType == "area"){ + s.fill.y2 = 90; + } + var theme = Theme.prototype.next.apply(this, arguments); + // cleanup + delete s.stroke; + s.fill.y2 = 75; + s.fill.space = "shape"; + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + themes.Charged.post = function(theme, elementType){ + theme = Theme.prototype.post.apply(this, arguments); + if((elementType == "slice" || elementType == "circle") && theme.series.fill && theme.series.fill.type == "radial"){ + theme.series.fill = gradutils.reverse(theme.series.fill); + } + return theme; + }; + + return themes.Charged; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Chris.js b/js/dojo-1.7.2/dojox/charting/themes/Chris.js new file mode 100644 index 0000000..4d85bce --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Chris.js @@ -0,0 +1,76 @@ +//>>built +define("dojox/charting/themes/Chris", ["../Theme", "dojox/gfx/gradutils", "./common"], function(Theme, gradutils, themes){ + + // created by Christopher Anderson + + var g = Theme.generateGradient, + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 100}; + + themes.Chris = new Theme({ + chart: { + fill: "#c1c1c1", + stroke: {color: "#666"} + }, + plotarea: { + fill: "#c1c1c1" + }, + series: { + stroke: {width: 2, color: "white"}, + outline: null, + fontColor: "#333" + }, + marker: { + stroke: {width: 2, color: "white"}, + outline: {width: 2, color: "white"}, + fontColor: "#333" + }, + seriesThemes: [ + {fill: g(defaultFill, "#01b717", "#238c01")}, // green + {fill: g(defaultFill, "#d04918", "#7c0344")}, // red + {fill: g(defaultFill, "#0005ec", "#002578")}, // blue + {fill: g(defaultFill, "#f9e500", "#786f00")}, // yellow + {fill: g(defaultFill, "#e27d00", "#773e00")}, // orange + {fill: g(defaultFill, "#00b5b0", "#005f5d")}, // teal + {fill: g(defaultFill, "#ac00cb", "#590060")} // purple + ], + markerThemes: [ + {fill: "#01b717", stroke: {color: "#238c01"}}, // green + {fill: "#d04918", stroke: {color: "#7c0344"}}, // red + {fill: "#0005ec", stroke: {color: "#002578"}}, // blue + {fill: "#f9e500", stroke: {color: "#786f00"}}, // yellow + {fill: "#e27d00", stroke: {color: "#773e00"}}, // orange + {fill: "#00b5b0", stroke: {color: "#005f5d"}}, // teal + {fill: "#ac00cb", stroke: {color: "#590060"}} // purple + ] + }); + + themes.Chris.next = function(elementType, mixin, doPost){ + var isLine = elementType == "line"; + if(isLine || elementType == "area"){ + // custom processing for lines: substitute colors + var s = this.seriesThemes[this._current % this.seriesThemes.length]; + s.fill.space = "plot"; + if(isLine){ + s.stroke = {color: s.fill.colors[1].color}; + s.outline = {width: 2, color: "white"}; + } + var theme = Theme.prototype.next.apply(this, arguments); + // cleanup + delete s.outline; + delete s.stroke; + s.fill.space = "shape"; + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + themes.Chris.post = function(theme, elementType){ + theme = Theme.prototype.post.apply(this, arguments); + if((elementType == "slice" || elementType == "circle") && theme.series.fill && theme.series.fill.type == "radial"){ + theme.series.fill = gradutils.reverse(theme.series.fill); + } + return theme; + }; + + return themes.Chris; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Claro.js b/js/dojo-1.7.2/dojox/charting/themes/Claro.js new file mode 100644 index 0000000..f9f96f2 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Claro.js @@ -0,0 +1,107 @@ +//>>built +define("dojox/charting/themes/Claro", ["../Theme", "dojox/gfx/gradutils", "./common"], function(Theme, gradutils, themes){ + // created by Tom Trenka + + var g = Theme.generateGradient, + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 100}; + + themes.Claro = new Theme({ + chart: { + fill: { + type: "linear", + x1: 0, x2: 0, y1: 0, y2: 100, + colors: [ + { offset: 0, color: "#dbdbdb" }, + { offset: 1, color: "#efefef" } + ] + }, + stroke: {color: "#b5bcc7"} + }, + plotarea: { + fill: { + type: "linear", + x1: 0, x2: 0, y1: 0, y2: 100, + colors: [ + { offset: 0, color: "#dbdbdb" }, + { offset: 1, color: "#efefef" } + ] + } + }, + axis:{ + stroke: { // the axis itself + color: "#888c76", + width: 1 + }, + tick: { // used as a foundation for all ticks + color: "#888c76", + position: "center", + font: "normal normal normal 7pt Verdana, Arial, sans-serif", // labels on axis + fontColor: "#888c76" // color of labels + } + }, + series: { + stroke: {width: 2.5, color: "#fff"}, + outline: null, + font: "normal normal normal 7pt Verdana, Arial, sans-serif", + fontColor: "#131313" + }, + marker: { + stroke: {width: 1.25, color: "#131313"}, + outline: {width: 1.25, color: "#131313"}, + font: "normal normal normal 8pt Verdana, Arial, sans-serif", + fontColor: "#131313" + }, + seriesThemes: [ + {fill: g(defaultFill, "#2a6ead", "#3a99f2")}, + {fill: g(defaultFill, "#613e04", "#996106")}, + {fill: g(defaultFill, "#0e3961", "#155896")}, + {fill: g(defaultFill, "#55aafa", "#3f7fba")}, + {fill: g(defaultFill, "#ad7b2a", "#db9b35")} + ], + markerThemes: [ + {fill: "#2a6ead", stroke: {color: "#fff"}}, + {fill: "#613e04", stroke: {color: "#fff"}}, + {fill: "#0e3961", stroke: {color: "#fff"}}, + {fill: "#55aafa", stroke: {color: "#fff"}}, + {fill: "#ad7b2a", stroke: {color: "#fff"}} + ] + }); + + themes.Claro.next = function(elementType, mixin, doPost){ + var isLine = elementType == "line"; + if(isLine || elementType == "area"){ + // custom processing for lines: substitute colors + var s = this.seriesThemes[this._current % this.seriesThemes.length], + m = this.markerThemes[this._current % this.markerThemes.length]; + s.fill.space = "plot"; + if(isLine){ + s.stroke = { width: 4, color: s.fill.colors[0].color}; + } + m.outline = { width: 1.25, color: m.fill }; + var theme = Theme.prototype.next.apply(this, arguments); + // cleanup + delete s.outline; + delete s.stroke; + s.fill.space = "shape"; + return theme; + } + else if(elementType == "candlestick"){ + var s = this.seriesThemes[this._current % this.seriesThemes.length]; + s.fill.space = "plot"; + s.stroke = { width: 1, color: s.fill.colors[0].color}; + var theme = Theme.prototype.next.apply(this, arguments); + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + themes.Claro.post = function(theme, elementType){ + theme = Theme.prototype.post.apply(this, arguments); + if((elementType == "slice" || elementType == "circle") && theme.series.fill && theme.series.fill.type == "radial"){ + theme.series.fill = gradutils.reverse(theme.series.fill); + } + return theme; + }; + + return themes.Claro; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/CubanShirts.js b/js/dojo-1.7.2/dojox/charting/themes/CubanShirts.js new file mode 100644 index 0000000..171af16 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/CubanShirts.js @@ -0,0 +1,17 @@ +//>>built +define("dojox/charting/themes/CubanShirts", ["../Theme", "./common"], function(Theme, themes){ + + // notes: colors generated by moving in 30 degree increments around the hue circle, + // at 90% saturation, using a B value of 75 (HSB model). + themes.CubanShirts=new Theme({ + colors: [ + "#d42d2a", + "#004f80", + "#989736", + "#2085c7", + "#7f7f33" + ] + }); + + return themes.CubanShirts; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Desert.js b/js/dojo-1.7.2/dojox/charting/themes/Desert.js new file mode 100644 index 0000000..6265d3a --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Desert.js @@ -0,0 +1,17 @@ +//>>built +define("dojox/charting/themes/Desert", ["../Theme", "./common"], function(Theme, themes){ + + // notes: colors generated by moving in 30 degree increments around the hue circle, + // at 90% saturation, using a B value of 75 (HSB model). + themes.Desert=new Theme({ + colors: [ + "#ffebd5", + "#806544", + "#fdc888", + "#80766b", + "#cda26e" + ] + }); + + return themes.Desert; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Distinctive.js b/js/dojo-1.7.2/dojox/charting/themes/Distinctive.js new file mode 100644 index 0000000..fefaf31 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Distinctive.js @@ -0,0 +1,43 @@ +//>>built +define("dojox/charting/themes/Distinctive", ["../Theme", "./common"], function(Theme, themes){ + + themes.Distinctive=new Theme({ + colors: [ + "#497c91", + "#ada9d6", + "#768b4e", + "#eeea99", + "#b39c53", + "#c28b69", + "#815454", + "#bebebe", + "#59a0bd", + "#c9c6e4", + "#677e13", + "#f0eebb", + "#e9c756", + "#cfb09b", + "#a05a5a", + "#d8d8d8", + "#9dc7d9", + "#7b78a4", + "#a8c179", + "#b7b35c", + "#ebcf81", + "#956649", + "#c99999", + "#868686", + "#c7e0e9", + "#8d88c7", + "#c0d0a0", + "#e8e667", + "#efdeb0", + "#b17044", + "#ddc0c0", + "#a5a5a5" + + ] + }); + + return themes.Distinctive; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Dollar.js b/js/dojo-1.7.2/dojox/charting/themes/Dollar.js new file mode 100644 index 0000000..6af8b5e --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Dollar.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/Dollar", ["../Theme", "./common"], function(Theme, themes){ + + themes.Dollar=new Theme({ + colors: [ + "#A4CE67", + "#739363", + "#6B824A", + "#343434", + "#636563" + ] + }); + + return themes.Dollar; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Electric.js b/js/dojo-1.7.2/dojox/charting/themes/Electric.js new file mode 100644 index 0000000..ce49b32 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Electric.js @@ -0,0 +1,89 @@ +//>>built +define("dojox/charting/themes/Electric", ["../Theme", "dojox/gfx/gradutils", "./common"], function(Theme, gradutils, themes){ + + var g = Theme.generateGradient, + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 75}; + + themes.Electric = new Theme({ + chart: { + fill: "#252525", + stroke: {color: "#252525"}, + pageStyle: {backgroundColor: "#252525", backgroundImage: "none", color: "#ccc"} + }, + plotarea: { + fill: "#252525" + }, + axis:{ + stroke: { // the axis itself + color: "#aaa", + width: 1 + }, + tick: { // used as a foundation for all ticks + color: "#777", + position: "center", + font: "normal normal normal 7pt Helvetica, Arial, sans-serif", // labels on axis + fontColor: "#777" // color of labels + } + }, + series: { + stroke: {width: 2, color: "#ccc"}, + outline: null, + font: "normal normal normal 8pt Helvetica, Arial, sans-serif", + fontColor: "#ccc" + }, + marker: { + stroke: {width: 3, color: "#ccc"}, + outline: null, + font: "normal normal normal 8pt Helvetica, Arial, sans-serif", + fontColor: "#ccc" + }, + seriesThemes: [ + {fill: g(defaultFill, "#004cbf", "#06f")}, + {fill: g(defaultFill, "#bf004c", "#f06")}, + {fill: g(defaultFill, "#43bf00", "#6f0")}, + {fill: g(defaultFill, "#7300bf", "#90f")}, + {fill: g(defaultFill, "#bf7300", "#f90")}, + {fill: g(defaultFill, "#00bf73", "#0f9")} + ], + markerThemes: [ + {fill: "#06f", stroke: {color: "#06f"}}, + {fill: "#f06", stroke: {color: "#f06"}}, + {fill: "#6f0", stroke: {color: "#6f0"}}, + {fill: "#90f", stroke: {color: "#90f"}}, + {fill: "#f90", stroke: {color: "#f90"}}, + {fill: "#0f9", stroke: {color: "#0f9"}} + ] + }); + + themes.Electric.next = function(elementType, mixin, doPost){ + var isLine = elementType == "line"; + if(isLine || elementType == "area"){ + // custom processing for lines: substitute colors + var s = this.seriesThemes[this._current % this.seriesThemes.length]; + s.fill.space = "plot"; + if(isLine){ + s.stroke = { width: 2.5, color: s.fill.colors[1].color}; + } + if(elementType == "area"){ + s.fill.y2 = 90; + } + var theme = Theme.prototype.next.apply(this, arguments); + // cleanup + delete s.stroke; + s.fill.y2 = 75; + s.fill.space = "shape"; + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + themes.Electric.post = function(theme, elementType){ + theme = Theme.prototype.post.apply(this, arguments); + if((elementType == "slice" || elementType == "circle") && theme.series.fill && theme.series.fill.type == "radial"){ + theme.series.fill = gradutils.reverse(theme.series.fill); + } + return theme; + }; + + return themes.Electric; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Grasshopper.js b/js/dojo-1.7.2/dojox/charting/themes/Grasshopper.js new file mode 100644 index 0000000..5d1392d --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Grasshopper.js @@ -0,0 +1,13 @@ +//>>built +define("dojox/charting/themes/Grasshopper", ["dojo/_base/lang","../Theme", "./common"], function(lang, Theme, themes){ + themes.Grasshopper=new Theme({ + colors: [ + "#208040", + "#40b657", + "#78c25e", + "#14401f", + "#64bd5f" + ] + }); + return themes.Grasshopper; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Grasslands.js b/js/dojo-1.7.2/dojox/charting/themes/Grasslands.js new file mode 100644 index 0000000..e6493c9 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Grasslands.js @@ -0,0 +1,17 @@ +//>>built +define("dojox/charting/themes/Grasslands", ["../Theme", "./common"], function(Theme, themes){ + + // notes: colors generated by moving in 30 degree increments around the hue circle, + // at 90% saturation, using a B value of 75 (HSB model). + themes.Grasslands=new Theme({ + colors: [ + "#70803a", + "#dde574", + "#788062", + "#b1cc5d", + "#eff2c2" + ] + }); + + return themes.Grasslands; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/GreySkies.js b/js/dojo-1.7.2/dojox/charting/themes/GreySkies.js new file mode 100644 index 0000000..c8c7fb1 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/GreySkies.js @@ -0,0 +1,7 @@ +//>>built +define("dojox/charting/themes/GreySkies", ["../Theme", "./common"], function(Theme, themes){ + + themes.GreySkies=new Theme(Theme._def); + + return themes.GreySkies; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Harmony.js b/js/dojo-1.7.2/dojox/charting/themes/Harmony.js new file mode 100644 index 0000000..4342cb1 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Harmony.js @@ -0,0 +1,42 @@ +//>>built +define("dojox/charting/themes/Harmony", ["../Theme", "./common"], function(Theme, themes){ + + themes.Harmony=new Theme({ + colors: [ + "#497c91", + "#59a0bd", + "#9dc7d9", + "#c7e0e9", + "#7b78a4", + "#8d88c7", + "#ada9d6", + "#c9c6e4", + "#768b4e", + "#677e13", + "#a8c179", + "#c0d0a0", + "#b7b35c", + "#e8e667", + "#eeea99", + "#f0eebb", + "#b39c53", + "#e9c756", + "#ebcf81", + "#efdeb0", + "#956649", + "#b17044", + "#c28b69", + "#cfb09b", + "#815454", + "#a05a5a", + "#c99999", + "#ddc0c0", + "#868686", + "#a5a5a5", + "#bebebe", + "#d8d8d8" + ] + }); + + return themes.Harmony; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/IndigoNation.js b/js/dojo-1.7.2/dojox/charting/themes/IndigoNation.js new file mode 100644 index 0000000..c34e083 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/IndigoNation.js @@ -0,0 +1,17 @@ +//>>built +define("dojox/charting/themes/IndigoNation", ["../Theme", "./common"], function(Theme, themes){ + + // notes: colors generated by moving in 30 degree increments around the hue circle, + // at 90% saturation, using a B value of 75 (HSB model). + themes.IndigoNation=new Theme({ + colors: [ + "#93a4d0", + "#3b4152", + "#687291", + "#9faed9", + "#8290b8" + ] + }); + + return themes.IndigoNation; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Ireland.js b/js/dojo-1.7.2/dojox/charting/themes/Ireland.js new file mode 100644 index 0000000..6c2c749 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Ireland.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/Ireland", ["../Theme", "./common"], function(Theme, themes){ + + themes.Ireland=new Theme({ + colors: [ + "#abdbcb", + "#435a51", + "#70998b", + "#78d596", + "#5f8074" + ] + }); + + return themes.Ireland; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Julie.js b/js/dojo-1.7.2/dojox/charting/themes/Julie.js new file mode 100644 index 0000000..f60188f --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Julie.js @@ -0,0 +1,69 @@ +//>>built +define("dojox/charting/themes/Julie", ["../Theme", "dojox/gfx/gradutils", "./common"], function(Theme, gradutils){ + + // created by Julie Santilli (Claro-based theme) + + var themes = dojox.charting.themes, g = Theme.generateGradient, + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 100}; + + themes.Julie = new Theme({ + seriesThemes: [ + {fill: g(defaultFill, "#59a0bd", "#497c91"), stroke: {color: "#22627d"}}, // blue + {fill: g(defaultFill, "#8d88c7", "#6c6d8e"), stroke: {color: "#8a84c5"}}, // purple + {fill: g(defaultFill, "#85a54a", "#768b4e"), stroke: {color: "#5b6d1f"}}, // green + {fill: g(defaultFill, "#e8e667", "#c6c361"), stroke: {color: "#918e38"}}, // yellow + {fill: g(defaultFill, "#e9c756", "#c7a223"), stroke: {color: "#947b30"}}, // orange + {fill: g(defaultFill, "#a05a5a", "#815454"), stroke: {color: "#572828"}}, // red + {fill: g(defaultFill, "#b17044", "#72543e"), stroke: {color: "#74482e"}}, // brown + {fill: g(defaultFill, "#a5a5a5", "#727272"), stroke: {color: "#535353"}}, // grey + + {fill: g(defaultFill, "#9dc7d9", "#59a0bd"), stroke: {color: "#22627d"}}, // blue + {fill: g(defaultFill, "#b7b3da", "#8681b3"), stroke: {color: "#8a84c5"}}, // purple + {fill: g(defaultFill, "#a8c179", "#85a54a"), stroke: {color: "#5b6d1f"}}, // green + {fill: g(defaultFill, "#eeea99", "#d6d456"), stroke: {color: "#918e38"}}, // yellow + {fill: g(defaultFill, "#ebcf81", "#e9c756"), stroke: {color: "#947b30"}}, // orange + {fill: g(defaultFill, "#c99999", "#a05a5a"), stroke: {color: "#572828"}}, // red + {fill: g(defaultFill, "#c28b69", "#7d5437"), stroke: {color: "#74482e"}}, // brown + {fill: g(defaultFill, "#bebebe", "#8c8c8c"), stroke: {color: "#535353"}}, // grey + + {fill: g(defaultFill, "#c7e0e9", "#92baca"), stroke: {color: "#22627d"}}, // blue + {fill: g(defaultFill, "#c9c6e4", "#ada9d6"), stroke: {color: "#8a84c5"}}, // purple + {fill: g(defaultFill, "#c0d0a0", "#98ab74"), stroke: {color: "#5b6d1f"}}, // green + {fill: g(defaultFill, "#f0eebb", "#dcd87c"), stroke: {color: "#918e38"}}, // yellow + {fill: g(defaultFill, "#efdeb0", "#ebcf81"), stroke: {color: "#947b30"}}, // orange + {fill: g(defaultFill, "#ddc0c0", "#c99999"), stroke: {color: "#572828"}}, // red + {fill: g(defaultFill, "#cfb09b", "#c28b69"), stroke: {color: "#74482e"}}, // brown + {fill: g(defaultFill, "#d8d8d8", "#bebebe"), stroke: {color: "#535353"}}, // grey + + {fill: g(defaultFill, "#ddeff5", "#a5c4cd"), stroke: {color: "#22627d"}}, // blue + {fill: g(defaultFill, "#dedcf0", "#b3afd3"), stroke: {color: "#8a84c5"}}, // purple + {fill: g(defaultFill, "#dfe9ca", "#c0d0a0"), stroke: {color: "#5b6d1f"}}, // green + {fill: g(defaultFill, "#f8f7db", "#e5e28f"), stroke: {color: "#918e38"}}, // yellow + {fill: g(defaultFill, "#f7f0d8", "#cfbd88"), stroke: {color: "#947b30"}}, // orange + {fill: g(defaultFill, "#eedede", "#caafaf"), stroke: {color: "#572828"}}, // red + {fill: g(defaultFill, "#e3cdbf", "#cfb09b"), stroke: {color: "#74482e"}}, // brown + {fill: g(defaultFill, "#efefef", "#cacaca"), stroke: {color: "#535353"}} // grey + ] + }); + + themes.Julie.next = function(elementType, mixin, doPost){ + if(elementType == "line" || elementType == "area"){ + var s = this.seriesThemes[this._current % this.seriesThemes.length]; + s.fill.space = "plot"; + var theme = Theme.prototype.next.apply(this, arguments); + s.fill.space = "shape"; + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + themes.Julie.post = function(theme, elementType){ + theme = Theme.prototype.post.apply(this, arguments); + if(elementType == "slice" && theme.series.fill && theme.series.fill.type == "radial"){ + theme.series.fill = gradutils.reverse(theme.series.fill); + } + return theme; + }; + + return themes.Julie; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/MiamiNice.js b/js/dojo-1.7.2/dojox/charting/themes/MiamiNice.js new file mode 100644 index 0000000..b600625 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/MiamiNice.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/MiamiNice", ["../Theme", "./common"], function(Theme, themes){ + + themes.MiamiNice=new Theme({ + colors: [ + "#7f9599", + "#45b8cc", + "#8ecfb0", + "#f8acac", + "#cc4482" + ] + }); + + return themes.MiamiNice; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Midwest.js b/js/dojo-1.7.2/dojox/charting/themes/Midwest.js new file mode 100644 index 0000000..4fcb9f7 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Midwest.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/Midwest", ["../Theme", "./common"], function(Theme, themes){ + + themes.Midwest=new Theme({ + colors: [ + "#927b51", + "#a89166", + "#80c31c", + "#bcdd5a", + "#aebc21" + ] + }); + + return themes.Midwest; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Minty.js b/js/dojo-1.7.2/dojox/charting/themes/Minty.js new file mode 100644 index 0000000..50c7e4f --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Minty.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/Minty", ["../Theme", "./common"], function(Theme, themes){ + + themes.Minty=new Theme({ + colors: [ + "#80ccbb", + "#539e8b", + "#335f54", + "#8dd1c2", + "#68c5ad" + ] + }); + + return themes.Minty; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/README b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/README new file mode 100644 index 0000000..dbf4c81 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/README @@ -0,0 +1,11 @@ +This directory contains a set of themes for the DojoX Charting +engine that are based on the visual stylings of the PlotKit +chart kit, created by Alastair Tse: + +http://www.liquidx.net/plotkit/ + +...whose work we admire. Consider these themes to not be a +ripoff of his fine work, but instead a true homage: his charts +are beautiful, and we stand in awe. + +--trt, 2007-06-08 diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/base.js b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/base.js new file mode 100644 index 0000000..4776c67 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/base.js @@ -0,0 +1,54 @@ +//>>built +define("dojox/charting/themes/PlotKit/base", ["dojo/_base/kernel","dojo/_base/lang","../../Theme", "../common"], + function(dojo, lang, Theme, themes){ + + // the baseline theme for all PlotKIt themes + var pk = lang.getObject("PlotKit", true, themes); + + pk.base = new Theme({ + chart:{ + stroke: null, + fill: "yellow" + }, + plotarea:{ + stroke: null, + fill: "yellow" + }, + axis:{ + stroke: {color:"#fff", width:1}, + line: {color:"#fff", width:.5}, + majorTick: {color: "#fff", width: .5, length: 6}, + minorTick: {color: "#fff", width: .5, length: 3}, + tick: {font: "normal normal normal 7pt Helvetica,Arial,sans-serif", fontColor: "#999"} + }, + series:{ + stroke: {width: 2.5, color:"#fff"}, + fill: "#666", + font: "normal normal normal 7.5pt Helvetica,Arial,sans-serif", // label + fontColor: "#666" + }, + marker:{ // any markers on a series. + stroke: {width: 2}, + fill: "#333", + font: "normal normal normal 7pt Helvetica,Arial,sans-serif", // label + fontColor: "#666" + }, + colors: ["red", "green", "blue"] + }); + + pk.base.next = function(elementType, mixin, doPost){ + var theme = Theme.prototype.next.apply(this, arguments); + if(elementType == "line"){ + theme.marker.outline = {width: 2, color: "#fff"}; + theme.series.stroke.width = 3.5; + theme.marker.stroke.width = 2; + } else if (elementType == "candlestick"){ + theme.series.stroke.width = 1; + } else { + theme.series.stroke.color = "#fff"; + } + return theme; + }; + + return pk; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/blue.js b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/blue.js new file mode 100644 index 0000000..e868e14 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/blue.js @@ -0,0 +1,8 @@ +//>>built +define("dojox/charting/themes/PlotKit/blue", ["./base", "../../Theme"], function(pk, Theme){ + pk.blue = pk.base.clone(); + pk.blue.chart.fill = pk.blue.plotarea.fill = "#e7eef6"; + pk.blue.colors = Theme.defineColors({hue: 217, saturation: 60, low: 40, high: 88}); + + return pk.blue; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/cyan.js b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/cyan.js new file mode 100644 index 0000000..7e21bae --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/cyan.js @@ -0,0 +1,8 @@ +//>>built +define("dojox/charting/themes/PlotKit/cyan", ["./base", "../../Theme"], function(pk, Theme){ + pk.cyan = pk.base.clone(); + pk.cyan.chart.fill = pk.cyan.plotarea.fill = "#e6f1f5"; + pk.cyan.colors = Theme.defineColors({hue: 194, saturation: 60, low: 40, high: 88}); + + return pk.cyan; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/green.js b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/green.js new file mode 100644 index 0000000..241f42a --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/green.js @@ -0,0 +1,8 @@ +//>>built +define("dojox/charting/themes/PlotKit/green", ["./base", "../../Theme"], function(pk, Theme){ + pk.green = pk.base.clone(); + pk.green.chart.fill = pk.green.plotarea.fill = "#eff5e6"; + pk.green.colors = Theme.defineColors({hue: 82, saturation: 60, low: 40, high: 88}); + + return pk.green; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/orange.js b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/orange.js new file mode 100644 index 0000000..22256bc --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/orange.js @@ -0,0 +1,8 @@ +//>>built +define("dojox/charting/themes/PlotKit/orange", ["./base", "../../Theme"], function(pk, Theme){ + pk.orange = pk.base.clone(); + pk.orange.chart.fill = pk.orange.plotarea.fill = "#f5eee6"; + pk.orange.colors = Theme.defineColors({hue: 31, saturation: 60, low: 40, high: 88}); + + return pk.orange; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/purple.js b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/purple.js new file mode 100644 index 0000000..30b3552 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/purple.js @@ -0,0 +1,8 @@ +//>>built +define("dojox/charting/themes/PlotKit/purple", ["./base", "../../Theme"], function(pk, Theme){ + pk.purple = pk.base.clone(); + pk.purple.chart.fill = pk.purple.plotarea.fill = "#eee6f5"; + pk.purple.colors = Theme.defineColors({hue: 271, saturation: 60, low: 40, high: 88}); + + return pk.purple; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PlotKit/red.js b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/red.js new file mode 100644 index 0000000..9b77eff --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PlotKit/red.js @@ -0,0 +1,8 @@ +//>>built +define("dojox/charting/themes/PlotKit/red", ["./base", "../../Theme"], function(pk, Theme){ + pk.red = pk.base.clone(); + pk.red.chart.fill = pk.red.plotarea.fill = "#f5e6e6"; + pk.red.colors = Theme.defineColors({hue: 1, saturation: 60, low: 40, high: 88}); + + return pk.red; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PrimaryColors.js b/js/dojo-1.7.2/dojox/charting/themes/PrimaryColors.js new file mode 100644 index 0000000..95d7860 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PrimaryColors.js @@ -0,0 +1,12 @@ +//>>built +define("dojox/charting/themes/PrimaryColors", ["../Theme", "./gradientGenerator", "./common"], function(Theme, gradientGenerator, themes){ + + var colors = ["#f00", "#0f0", "#00f", "#ff0", "#0ff", "#f0f", "./common"], + defaultFill = {type: "linear", space: "plot", x1: 0, y1: 0, x2: 0, y2: 100}; + + themes.PrimaryColors = new Theme({ + seriesThemes: gradientGenerator.generateMiniTheme(colors, defaultFill, 90, 40, 25) + }); + + return themes.PrimaryColors; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/PurpleRain.js b/js/dojo-1.7.2/dojox/charting/themes/PurpleRain.js new file mode 100644 index 0000000..8be3dc3 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/PurpleRain.js @@ -0,0 +1,17 @@ +//>>built +define("dojox/charting/themes/PurpleRain", ["../Theme", "./common"], function(Theme, themes){ + + // notes: colors generated by moving in 30 degree increments around the hue circle, + // at 90% saturation, using a B value of 75 (HSB model). + themes.PurpleRain=new Theme({ + colors: [ + "#4879bc", + "#ef446f", + "#3f58a7", + "#8254a2", + "#4956a6" + ] + }); + + return themes.PurpleRain; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/README b/js/dojo-1.7.2/dojox/charting/themes/README new file mode 100644 index 0000000..9a3725d --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/README @@ -0,0 +1,5 @@ +Theme authors: + +GreySkies, Shrooms, PlotKit (all): Tom Trenka (ttrenka AT gmail.com) +ET (all): Alex Russell (alex AT dojotoolkit.org) +Ireland, SageToLime, Minty: Damon Dimmick (SitePen, Inc.) diff --git a/js/dojo-1.7.2/dojox/charting/themes/Renkoo.js b/js/dojo-1.7.2/dojox/charting/themes/Renkoo.js new file mode 100644 index 0000000..ef883e1 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Renkoo.js @@ -0,0 +1,84 @@ +//>>built +define("dojox/charting/themes/Renkoo", ["../Theme", "dojox/gfx/gradutils", "./common"], function(Theme, gradutils, themes){ + + // created by Tom Trenka + + var g = Theme.generateGradient, + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 150}; + + themes.Renkoo = new Theme({ + chart: { + fill: "#123666", + pageStyle: {backgroundColor: "#123666", backgroundImage: "none", color: "#95afdb"} + }, + plotarea: { + fill: "#123666" + }, + axis:{ + stroke: { // the axis itself + color: "#95afdb", + width: 1 + }, + tick: { // used as a foundation for all ticks + color: "#95afdb", + position: "center", + font: "normal normal normal 7pt Lucida Grande, Helvetica, Arial, sans-serif", // labels on axis + fontColor: "#95afdb" // color of labels + } + }, + series: { + stroke: {width: 2.5, color: "#123666"}, + outline: null, + font: "normal normal normal 8pt Lucida Grande, Helvetica, Arial, sans-serif", // labels on axis + fontColor: "#95afdb" + }, + marker: { + stroke: {width: 2.5, color: "#ccc"}, + outline: null, + font: "normal normal normal 8pt Lucida Grande, Helvetica, Arial, sans-serif", // labels on axis + fontColor: "#95afdb" + }, + seriesThemes: [ + {fill: g(defaultFill, "#e7e391", "#f8f7de")}, + {fill: g(defaultFill, "#ffb6b6", "#ffe8e8")}, + {fill: g(defaultFill, "#bcda7d", "#eef7da")}, + {fill: g(defaultFill, "#d5d5d5", "#f4f4f4")}, + {fill: g(defaultFill, "#c1e3fd", "#e4f3ff")} + ], + markerThemes: [ + {fill: "#fcfcf3", stroke: {color: "#e7e391"}}, + {fill: "#fff1f1", stroke: {color: "#ffb6b6"}}, + {fill: "#fafdf4", stroke: {color: "#bcda7d"}}, + {fill: "#fbfbfb", stroke: {color: "#d5d5d5"}}, + {fill: "#f3faff", stroke: {color: "#c1e3fd"}} + ] + }); + + themes.Renkoo.next = function(elementType, mixin, doPost){ + if("slice,column,bar".indexOf(elementType) == -1){ + // custom processing to substitute colors + var s = this.seriesThemes[this._current % this.seriesThemes.length]; + s.fill.space = "plot"; + s.stroke = { width: 2, color: s.fill.colors[0].color}; + if(elementType == "line" || elementType == "area"){ + s.stroke.width = 4; + } + var theme = Theme.prototype.next.apply(this, arguments); + // cleanup + delete s.stroke; + s.fill.space = "shape"; + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + themes.Renkoo.post = function(theme, elementType){ + theme = Theme.prototype.post.apply(this, arguments); + if((elementType == "slice" || elementType == "circle") && theme.series.fill && theme.series.fill.type == "radial"){ + theme.series.fill = gradutils.reverse(theme.series.fill); + } + return theme; + }; + + return themes.Renkoo; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/RoyalPurples.js b/js/dojo-1.7.2/dojox/charting/themes/RoyalPurples.js new file mode 100644 index 0000000..f652e48 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/RoyalPurples.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/RoyalPurples", ["../Theme", "./common"], function(Theme, themes){ + + themes.RoyalPurples=new Theme({ + colors: [ + "#473980", + "#685aa7", + "#7970b3", + "#231c3f", + "#7267ae" + ] + }); + + return themes.RoyalPurples; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/SageToLime.js b/js/dojo-1.7.2/dojox/charting/themes/SageToLime.js new file mode 100644 index 0000000..f295b81 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/SageToLime.js @@ -0,0 +1,20 @@ +//>>built +define("dojox/charting/themes/SageToLime", ["../Theme", "./common"], function(Theme, themes){ + + themes.SageToLime=new Theme({ + colors: [ + "#abdbcb", + "#435a51", + "#70998b", + "#5f8074", + "#80ccbb", + "#539e8b", + "#78a596", + "#335f54", + "#8dd1c2", + "#68c5ad" + ] + }); + + return themes.SageToLime; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Shrooms.js b/js/dojo-1.7.2/dojox/charting/themes/Shrooms.js new file mode 100644 index 0000000..35305cf --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Shrooms.js @@ -0,0 +1,23 @@ +//>>built +define("dojox/charting/themes/Shrooms", ["../Theme", "./common"], function(Theme, themes){ + // notes: colors generated by moving in 30 degree increments around the hue circle, + // at 90% saturation, using a B value of 75 (HSB model). + themes.Shrooms = new Theme({ + colors: [ + "#bf1313", // 0 + "#69bf13", // 90 + "#13bfbf", // 180 + "#6913bf", // 270 + "#bf6913", // 30 + "#13bf13", // 120 + "#1369bf", // 210 + "#bf13bf", // 300 + "#bfbf13", // 60 + "#13bf69", // 150 + "#1313bf", // 240 + "#bf1369" // 330 + ] + }); + + return themes.Shrooms; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/ThreeD.js b/js/dojo-1.7.2/dojox/charting/themes/ThreeD.js new file mode 100644 index 0000000..8085eb5 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/ThreeD.js @@ -0,0 +1,44 @@ +//>>built +define("dojox/charting/themes/ThreeD", ["dojox","dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array", "../Theme", "./gradientGenerator", "./PrimaryColors", "dojo/colors" /* for sanitize */, "./common"], + function(dojox, kernel, lang, ArrayUtil, Theme, gradientGenerator, PrimaryColors, themes){ + + var colors = ["#f00", "#0f0", "#00f", "#ff0", "#0ff", "#f0f", "./common"], // the same is in PrimaryColors + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 100, y2: 0}, + // 3D cylinder map is calculated using dojox.gfx3d + cyl3dMap = [ + {o: 0.00, i: 174}, {o: 0.08, i: 231}, {o: 0.18, i: 237}, {o: 0.30, i: 231}, + {o: 0.39, i: 221}, {o: 0.49, i: 206}, {o: 0.58, i: 187}, {o: 0.68, i: 165}, + {o: 0.80, i: 128}, {o: 0.90, i: 102}, {o: 1.00, i: 174} + ], + hiliteIndex = 2, hiliteIntensity = 100, lumStroke = 50, + cyl3dFills = ArrayUtil.map(colors, function(c){ + var fill = lang.delegate(defaultFill), + colors = fill.colors = gradientGenerator.generateGradientByIntensity(c, cyl3dMap), + hilite = colors[hiliteIndex].color; + // add highlight + hilite.r += hiliteIntensity; + hilite.g += hiliteIntensity; + hilite.b += hiliteIntensity; + hilite.sanitize(); + return fill; + }); + + themes.ThreeD = PrimaryColors.clone(); + themes.ThreeD.series.shadow = {dx: 1, dy: 1, width: 3, color: [0, 0, 0, 0.15]}; + + themes.ThreeD.next = function(elementType, mixin, doPost){ + if(elementType == "bar" || elementType == "column"){ + // custom processing for bars and columns: substitute fills + var index = this._current % this.seriesThemes.length, + s = this.seriesThemes[index], old = s.fill; + s.fill = cyl3dFills[index]; + var theme = Theme.prototype.next.apply(this, arguments); + // cleanup + s.fill = old; + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + return themes.ThreeD; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Tom.js b/js/dojo-1.7.2/dojox/charting/themes/Tom.js new file mode 100644 index 0000000..ccb27ab --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Tom.js @@ -0,0 +1,86 @@ +//>>built +define("dojox/charting/themes/Tom", ["../Theme", "dojox/gfx/gradutils", "./common"], function(Theme, gradutils, themes){ + + // created by Tom Trenka + + var g = Theme.generateGradient, + defaultFill = {type: "linear", space: "shape", x1: 0, y1: 0, x2: 0, y2: 100}; + + themes.Tom = new Theme({ + chart: { + fill: "#181818", + stroke: {color: "#181818"}, + pageStyle: {backgroundColor: "#181818", backgroundImage: "none", color: "#eaf2cb"} + }, + plotarea: { + fill: "#181818" + }, + axis:{ + stroke: { // the axis itself + color: "#a0a68b", + width: 1 + }, + tick: { // used as a foundation for all ticks + color: "#888c76", + position: "center", + font: "normal normal normal 7pt Helvetica, Arial, sans-serif", // labels on axis + fontColor: "#888c76" // color of labels + } + }, + series: { + stroke: {width: 2.5, color: "#eaf2cb"}, + outline: null, + font: "normal normal normal 8pt Helvetica, Arial, sans-serif", + fontColor: "#eaf2cb" + }, + marker: { + stroke: {width: 1.25, color: "#eaf2cb"}, + outline: {width: 1.25, color: "#eaf2cb"}, + font: "normal normal normal 8pt Helvetica, Arial, sans-serif", + fontColor: "#eaf2cb" + }, + seriesThemes: [ + {fill: g(defaultFill, "#bf9e0a", "#ecc20c")}, + {fill: g(defaultFill, "#73b086", "#95e5af")}, + {fill: g(defaultFill, "#c7212d", "#ed2835")}, + {fill: g(defaultFill, "#87ab41", "#b6e557")}, + {fill: g(defaultFill, "#b86c25", "#d37d2a")} + ], + markerThemes: [ + {fill: "#bf9e0a", stroke: {color: "#ecc20c"}}, + {fill: "#73b086", stroke: {color: "#95e5af"}}, + {fill: "#c7212d", stroke: {color: "#ed2835"}}, + {fill: "#87ab41", stroke: {color: "#b6e557"}}, + {fill: "#b86c25", stroke: {color: "#d37d2a"}} + ] + }); + + themes.Tom.next = function(elementType, mixin, doPost){ + var isLine = elementType == "line"; + if(isLine || elementType == "area"){ + // custom processing for lines: substitute colors + var s = this.seriesThemes[this._current % this.seriesThemes.length]; + s.fill.space = "plot"; + if(isLine){ + s.stroke = { width: 4, color: s.fill.colors[0].color}; + } + var theme = Theme.prototype.next.apply(this, arguments); + // cleanup + delete s.outline; + delete s.stroke; + s.fill.space = "shape"; + return theme; + } + return Theme.prototype.next.apply(this, arguments); + }; + + themes.Tom.post = function(theme, elementType){ + theme = Theme.prototype.post.apply(this, arguments); + if((elementType == "slice" || elementType == "circle") && theme.series.fill && theme.series.fill.type == "radial"){ + theme.series.fill = gradutils.reverse(theme.series.fill); + } + return theme; + }; + + return themes.Tom; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Tufte.js b/js/dojo-1.7.2/dojox/charting/themes/Tufte.js new file mode 100644 index 0000000..2b1cf44 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Tufte.js @@ -0,0 +1,55 @@ +//>>built +define("dojox/charting/themes/Tufte", ["../Theme", "dojo/_base/Color", "./common"], function(Theme, Color, themes){ + /* + A charting theme based on the principles championed by + Edward Tufte. By Alex Russell, Dojo Project Lead. + */ + themes.Tufte = new Theme({ + chart: { + stroke: null, + fill: "inherit" + }, + plotarea: { + // stroke: { width: 0.2, color: "#666666" }, + stroke: null, + fill: "transparent" + }, + axis: { + stroke: {width: 1, color: "#ccc"}, + majorTick:{ + color: "black", + width: 1, + length: 5 + }, + minorTick: { + color: "#666", + width: 1, + length: 2 + }, + font: "normal normal normal 8pt Tahoma", + fontColor: "#999" + }, + series: { + outline: null, + stroke: {width: 1, color: "black"}, + // fill: "#3b444b", + fill: new Color([0x3b, 0x44, 0x4b, 0.85]), + font: "normal normal normal 7pt Tahoma", + fontColor: "#717171" + }, + marker: { + stroke: {width: 1, color: "black"}, + fill: "#333", + font: "normal normal normal 7pt Tahoma", + fontColor: "black" + }, + colors:[ + Color.fromHex("#8a8c8f"), + Color.fromHex("#4b4b4b"), + Color.fromHex("#3b444b"), + Color.fromHex("#2e2d30"), + Color.fromHex("#000000") + ] + }); + return themes.Tufte; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/WatersEdge.js b/js/dojo-1.7.2/dojox/charting/themes/WatersEdge.js new file mode 100644 index 0000000..8714a14 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/WatersEdge.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/WatersEdge", ["../Theme", "./common"], function(Theme, themes){ + + themes.WatersEdge = new Theme({ + colors: [ + "#437cc0", + "#6256a5", + "#4552a3", + "#43c4f2", + "#4b66b0" + ] + }); + + return themes.WatersEdge; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/Wetland.js b/js/dojo-1.7.2/dojox/charting/themes/Wetland.js new file mode 100644 index 0000000..8fc0529 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/Wetland.js @@ -0,0 +1,15 @@ +//>>built +define("dojox/charting/themes/Wetland", ["../Theme", "./common"], function(Theme, themes){ + + themes.Wetland = new Theme({ + colors: [ + "#bfbc64", + "#737130", + "#73373b", + "#7dafca", + "#8d3c42" + ] + }); + + return themes.Wetland; +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/common.js b/js/dojo-1.7.2/dojox/charting/themes/common.js new file mode 100644 index 0000000..7e2fd65 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/common.js @@ -0,0 +1,4 @@ +//>>built +define("dojox/charting/themes/common", ["dojo/_base/lang"], function(lang){ + return lang.getObject("dojox.charting.themes", true); +}); diff --git a/js/dojo-1.7.2/dojox/charting/themes/gradientGenerator.js b/js/dojo-1.7.2/dojox/charting/themes/gradientGenerator.js new file mode 100644 index 0000000..e649a31 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/themes/gradientGenerator.js @@ -0,0 +1,82 @@ +//>>built +define("dojox/charting/themes/gradientGenerator", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/Color", "../Theme", "dojox/color/_base", "./common"], + function(lang, arr, Color, Theme, dxcolor, themes){ + + var gg = lang.getObject("gradientGenerator", true, themes); + + gg.generateFills = function(colors, fillPattern, lumFrom, lumTo){ + // summary: + // generates 2-color gradients using pure colors, a fill pattern, and two luminance values + // colors: Array: + // Array of colors to generate gradients for each. + // fillPattern: Object: + // Gradient fill descriptor which colors list will be generated. + // lumFrom: Number: + // Initial luminance value (0-100). + // lumTo: Number: + // Final luminance value (0-100). + return arr.map(colors, function(c){ // Array + return Theme.generateHslGradient(c, fillPattern, lumFrom, lumTo); + }); + }; + + gg.updateFills = function(themes, fillPattern, lumFrom, lumTo){ + // summary: + // transforms solid color fills into 2-color gradients using a fill pattern, and two luminance values + // themes: Array: + // Array of mini-themes (usually series themes or marker themes), which fill will be transformed. + // fillPattern: Object: + // Gradient fill descriptor which colors list will be generated. + // lumFrom: Number: + // Initial luminance value (0-100). + // lumTo: Number: + // Final luminance value (0-100). + arr.forEach(themes, function(t){ + if(t.fill && !t.fill.type){ + t.fill = Theme.generateHslGradient(t.fill, fillPattern, lumFrom, lumTo); + } + }); + }; + + gg.generateMiniTheme = function(colors, fillPattern, lumFrom, lumTo, lumStroke){ + // summary: + // generates mini-themes with 2-color gradients using colors, a fill pattern, and three luminance values + // colors: Array: + // Array of colors to generate gradients for each. + // fillPattern: Object: + // Gradient fill descriptor which colors list will be generated. + // lumFrom: Number: + // Initial luminance value (0-100). + // lumTo: Number: + // Final luminance value (0-100). + // lumStroke: Number: + // Stroke luminance value (0-100). + return arr.map(colors, function(c){ // Array + c = new dxcolor.Color(c); + return { + fill: Theme.generateHslGradient(c, fillPattern, lumFrom, lumTo), + stroke: {color: Theme.generateHslColor(c, lumStroke)} + } + }); + }; + + gg.generateGradientByIntensity = function(color, intensityMap){ + // summary: + // generates gradient colors using an intensity map + // color: dojo.Color: + // Color to use to generate gradients. + // intensityMap: Array: + // Array of tuples {o, i}, where o is a gradient offset (0-1), + // and i is an intensity (0-255). + color = new Color(color); + return arr.map(intensityMap, function(stop){ // Array + var s = stop.i / 255; + return { + offset: stop.o, + color: new Color([color.r * s, color.g * s, color.b * s, color.a]) + }; + }); + } + + return gg; +}); diff --git a/js/dojo-1.7.2/dojox/charting/widget/BidiSupport.js b/js/dojo-1.7.2/dojox/charting/widget/BidiSupport.js new file mode 100644 index 0000000..9dc3248 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/widget/BidiSupport.js @@ -0,0 +1,93 @@ +//>>built +define("dojox/charting/widget/BidiSupport", ["dojo/dom", "dojo/_base/lang", "dojo/_base/html", "dojo/_base/array", "dojo/_base/connect", "dojo/query", + "dijit/_BidiSupport", "../BidiSupport", "dijit/registry", "./Chart", "./Legend"], + function(dom, lang, html, arrayUtil, hub, query, dBidi, cBidi, widgetManager, Chart, Legend){ + + // patch only if present + if( Legend ){ + lang.extend(Legend, { + // summary: + // Add support for bidi scripts in legend. + // description: + // Since dojox.charting.widget.Legend inherits from _Widget use the bidi support + // that introduced there. + + postMixInProperties: function(){ + // summary: + // Connect the setter of textDir legend to setTextDir of the chart, + // so _setTextDirAttr of the legend will be called after setTextDir of the chart is called. + // tags: + // private + + // find the chart that is the owner of this legend, use it's + // textDir + if(!this.chart){ + if(!this.chartRef){ return; } + var chart = widgetManager.byId(this.chartRef); + if(!chart){ + var node = dom.byId(this.chartRef); + if(node){ + chart = widgetManager.byNode(node); + }else{ + return; + } + } + this.textDir = chart.chart.textDir; + hub.connect(chart.chart, "setTextDir", this, "_setTextDirAttr"); + + }else{ + this.textDir = this.chart.textDir; + hub.connect(this.chart, "setTextDir", this, "_setTextDirAttr"); + + } + }, + + _setTextDirAttr: function(/*String*/ textDir){ + // summary: + // Setter for textDir. + // description: + // Users shouldn't call this function; they should be calling + // set('textDir', value) + // tags: + // private + + // only if new textDir is different from the old one + if(validateTextDir(textDir) != null){ + if(this.textDir != textDir){ + this._set("textDir", textDir); + // get array of all the labels + var legendLabels = query(".dojoxLegendText", this._tr); + // for every label calculate it's new dir. + arrayUtil.forEach(legendLabels, function(label){ + label.dir = this.getTextDir(label.innerHTML, label.dir); + }, this); + } + } + } + }); + } + + // patch only if present + if( Chart ){ + lang.extend( Chart ,{ + postMixInProperties: function(){ + // set initial textDir of the chart, if passed in the creation use that value + // else use default value, following the GUI direction, this.chart doesn't exist yet + // so can't use set("textDir", textDir). This passed to this.chart in it's future creation. + this.textDir = this.params["textDir"] ? this.params["textDir"] : this.params["dir"]; + }, + + _setTextDirAttr: function(/*String*/ textDir){ + if(validateTextDir(textDir) != null){ + this._set("textDir", textDir); + this.chart.setTextDir(textDir); + } + } + }); + } + + function validateTextDir(textDir){ + return /^(ltr|rtl|auto)$/.test(textDir) ? textDir : null; + } + +}); diff --git a/js/dojo-1.7.2/dojox/charting/widget/Chart.js b/js/dojo-1.7.2/dojox/charting/widget/Chart.js new file mode 100644 index 0000000..1b35849 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/widget/Chart.js @@ -0,0 +1,272 @@ +//>>built +define("dojox/charting/widget/Chart", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array","dojo/_base/html","dojo/_base/declare", "dojo/query", + "dijit/_Widget", "../Chart", "dojox/lang/utils", "dojox/lang/functional","dojox/lang/functional/lambda", + "dijit/_base/manager"], + function(kernel, lang, arr, html, declare, query, Widget, Chart, du, df, dfl){ +/*===== +var Widget = dijit._Widget; +=====*/ + var collectParams, collectAxisParams, collectPlotParams, + collectActionParams, collectDataParams, + notNull = function(o){ return o; }, + dc = lang.getObject("dojox.charting"); + + var ChartWidget = declare("dojox.charting.widget.Chart", Widget, { + // parameters for the markup + + // theme for the chart + theme: null, + + // margins for the chart: {l: 10, r: 10, t: 10, b: 10} + margins: null, + + // chart area, define them as undefined to: + // allow the parser to take them into account + // but make sure they have no defined value to not override theme + stroke: undefined, + fill: undefined, + + // methods + + buildRendering: function(){ + this.inherited(arguments); + + n = this.domNode; + + // collect chart parameters + var axes = query("> .axis", n).map(collectAxisParams).filter(notNull), + plots = query("> .plot", n).map(collectPlotParams).filter(notNull), + actions = query("> .action", n).map(collectActionParams).filter(notNull), + series = query("> .series", n).map(collectDataParams).filter(notNull); + + // build the chart + n.innerHTML = ""; + var c = this.chart = new Chart(n, { + margins: this.margins, + stroke: this.stroke, + fill: this.fill, + textDir: this.textDir + }); + + // add collected parameters + if(this.theme){ + c.setTheme(this.theme); + } + axes.forEach(function(axis){ + c.addAxis(axis.name, axis.kwArgs); + }); + plots.forEach(function(plot){ + c.addPlot(plot.name, plot.kwArgs); + }); + + this.actions = actions.map(function(action){ + return new action.action(c, action.plot, action.kwArgs); + }); + + var render = df.foldl(series, function(render, series){ + if(series.type == "data"){ + c.addSeries(series.name, series.data, series.kwArgs); + render = true; + }else{ + c.addSeries(series.name, [0], series.kwArgs); + var kw = {}; + du.updateWithPattern( + kw, + series.kwArgs, + { + "query": "", + "queryOptions": null, + "start": 0, + "count": 1 //, + // "sort": [] + }, + true + ); + if(series.kwArgs.sort){ + // sort is a complex object type and doesn't survive coercian + kw.sort = lang.clone(series.kwArgs.sort); + } + lang.mixin(kw, { + onComplete: function(data){ + var values; + if("valueFn" in series.kwArgs){ + var fn = series.kwArgs.valueFn; + values = arr.map(data, function(x){ + return fn(series.data.getValue(x, series.field, 0)); + }); + }else{ + values = arr.map(data, function(x){ + return series.data.getValue(x, series.field, 0); + }); + } + c.addSeries(series.name, values, series.kwArgs).render(); + } + }); + series.data.fetch(kw); + } + return render; + }, false); + if(render){ c.render(); } + }, + destroy: function(){ + // summary: properly destroy the widget + this.chart.destroy(); + this.inherited(arguments); + }, + resize: function(box){ + // summary: + // Resize the widget. + // description: + // Resize the domNode and the widget surface to the dimensions of a box of the following form: + // `{ l: 50, t: 200, w: 300: h: 150 }` + // If no box is provided, resize the surface to the marginBox of the domNode. + // box: + // If passed, denotes the new size of the widget. + this.chart.resize(box); + } + }); + + collectParams = function(node, type, kw){ + var dp = eval("(" + type + ".prototype.defaultParams)"); + var x, attr; + for(x in dp){ + if(x in kw){ continue; } + attr = node.getAttribute(x); + kw[x] = du.coerceType(dp[x], attr == null || typeof attr == "undefined" ? dp[x] : attr); + } + var op = eval("(" + type + ".prototype.optionalParams)"); + for(x in op){ + if(x in kw){ continue; } + attr = node.getAttribute(x); + if(attr != null){ + kw[x] = du.coerceType(op[x], attr); + } + } + }; + + collectAxisParams = function(node){ + var name = node.getAttribute("name"), type = node.getAttribute("type"); + if(!name){ return null; } + var o = {name: name, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dc.axis2d[type]){ + type = dojo._scopeName + "x.charting.axis2d." + type; + } + var axis = eval("(" + type + ")"); + if(axis){ kw.type = axis; } + }else{ + type = dojo._scopeName + "x.charting.axis2d.Default"; + } + collectParams(node, type, kw); + // compatibility conversions + if(kw.font || kw.fontColor){ + if(!kw.tick){ + kw.tick = {}; + } + if(kw.font){ + kw.tick.font = kw.font; + } + if(kw.fontColor){ + kw.tick.fontColor = kw.fontColor; + } + } + return o; + }; + + collectPlotParams = function(node){ + // var name = d.attr(node, "name"), type = d.attr(node, "type"); + var name = node.getAttribute("name"), type = node.getAttribute("type"); + if(!name){ return null; } + var o = {name: name, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dc.plot2d && dc.plot2d[type]){ + type = dojo._scopeName + "x.charting.plot2d." + type; + } + var plot = eval("(" + type + ")"); + if(plot){ kw.type = plot; } + }else{ + type = dojo._scopeName + "x.charting.plot2d.Default"; + } + collectParams(node, type, kw); + return o; + }; + + collectActionParams = function(node){ + // var plot = d.attr(node, "plot"), type = d.attr(node, "type"); + var plot = node.getAttribute("plot"), type = node.getAttribute("type"); + if(!plot){ plot = "default"; } + var o = {plot: plot, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dc.action2d[type]){ + type = dojo._scopeName + "x.charting.action2d." + type; + } + var action = eval("(" + type + ")"); + if(!action){ return null; } + o.action = action; + }else{ + return null; + } + collectParams(node, type, kw); + return o; + }; + + collectDataParams = function(node){ + var ga = lang.partial(html.attr, node); + var name = ga("name"); + if(!name){ return null; } + var o = { name: name, kwArgs: {} }, kw = o.kwArgs, t; + t = ga("plot"); + if(t != null){ kw.plot = t; } + t = ga("marker"); + if(t != null){ kw.marker = t; } + t = ga("stroke"); + if(t != null){ kw.stroke = eval("(" + t + ")"); } + t = ga("outline"); + if(t != null){ kw.outline = eval("(" + t + ")"); } + t = ga("shadow"); + if(t != null){ kw.shadow = eval("(" + t + ")"); } + t = ga("fill"); + if(t != null){ kw.fill = eval("(" + t + ")"); } + t = ga("font"); + if(t != null){ kw.font = t; } + t = ga("fontColor"); + if(t != null){ kw.fontColor = eval("(" + t + ")"); } + t = ga("legend"); + if(t != null){ kw.legend = t; } + t = ga("data"); + if(t != null){ + o.type = "data"; + o.data = t ? arr.map(String(t).split(','), Number) : []; + return o; + } + t = ga("array"); + if(t != null){ + o.type = "data"; + o.data = eval("(" + t + ")"); + return o; + } + t = ga("store"); + if(t != null){ + o.type = "store"; + o.data = eval("(" + t + ")"); + t = ga("field"); + o.field = t != null ? t : "value"; + t = ga("query"); + if(!!t){ kw.query = t; } + t = ga("queryOptions"); + if(!!t){ kw.queryOptions = eval("(" + t + ")"); } + t = ga("start"); + if(!!t){ kw.start = Number(t); } + t = ga("count"); + if(!!t){ kw.count = Number(t); } + t = ga("sort"); + if(!!t){ kw.sort = eval("("+t+")"); } + t = ga("valueFn"); + if(!!t){ kw.valueFn = dfl.lambda(t); } + return o; + } + return null; + }; + + return ChartWidget; +}); diff --git a/js/dojo-1.7.2/dojox/charting/widget/Chart2D.js b/js/dojo-1.7.2/dojox/charting/widget/Chart2D.js new file mode 100644 index 0000000..9d21ff8 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/widget/Chart2D.js @@ -0,0 +1,15 @@ +/* + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. + Available via Academic Free License >= 2.1 OR the modified BSD license. + see: http://dojotoolkit.org/license for details +*/ + +/* + This is an optimized version of Dojo, built for deployment and not for + development. To get sources and documentation, please visit: + + http://dojotoolkit.org +*/ + +//>>built +require({cache:{"dojox/charting/plot2d/_PlotEvents":function(){define("dojox/charting/plot2d/_PlotEvents",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","dojo/_base/connect"],function(_1,_2,_3,_4){return _3("dojox.charting.plot2d._PlotEvents",null,{constructor:function(){this._shapeEvents=[];this._eventSeries={};},destroy:function(){this.resetEvents();this.inherited(arguments);},plotEvent:function(o){},raiseEvent:function(o){this.plotEvent(o);var t=_1.delegate(o);t.originalEvent=o.type;t.originalPlot=o.plot;t.type="onindirect";_2.forEach(this.chart.stack,function(_5){if(_5!==this&&_5.plotEvent){t.plot=_5;_5.plotEvent(t);}},this);},connect:function(_6,_7){this.dirty=true;return _4.connect(this,"plotEvent",_6,_7);},events:function(){return !!this.plotEvent.after;},resetEvents:function(){if(this._shapeEvents.length){_2.forEach(this._shapeEvents,function(_8){_8.shape.disconnect(_8.handle);});this._shapeEvents=[];}this.raiseEvent({type:"onplotreset",plot:this});},_connectSingleEvent:function(o,_9){this._shapeEvents.push({shape:o.eventMask,handle:o.eventMask.connect(_9,this,function(e){o.type=_9;o.event=e;this.raiseEvent(o);o.event=null;})});},_connectEvents:function(o){if(o){o.chart=this.chart;o.plot=this;o.hAxis=this.hAxis||null;o.vAxis=this.vAxis||null;o.eventMask=o.eventMask||o.shape;this._connectSingleEvent(o,"onmouseover");this._connectSingleEvent(o,"onmouseout");this._connectSingleEvent(o,"onclick");}},_reconnectEvents:function(_a){var a=this._eventSeries[_a];if(a){_2.forEach(a,this._connectEvents,this);}},fireEvent:function(_b,_c,_d,_e){var s=this._eventSeries[_b];if(s&&s.length&&_d<s.length){var o=s[_d];o.type=_c;o.event=_e||null;this.raiseEvent(o);o.event=null;}}});});},"dojo/uacss":function(){define(["./dom-geometry","./_base/lang","./ready","./_base/sniff","./_base/window"],function(_f,_10,_11,has,_12){var _13=_12.doc.documentElement,ie=has("ie"),_14=has("opera"),maj=Math.floor,ff=has("ff"),_15=_f.boxModel.replace(/-/,""),_16={"dj_ie":ie,"dj_ie6":maj(ie)==6,"dj_ie7":maj(ie)==7,"dj_ie8":maj(ie)==8,"dj_ie9":maj(ie)==9,"dj_quirks":has("quirks"),"dj_iequirks":ie&&has("quirks"),"dj_opera":_14,"dj_khtml":has("khtml"),"dj_webkit":has("webkit"),"dj_safari":has("safari"),"dj_chrome":has("chrome"),"dj_gecko":has("mozilla"),"dj_ff3":maj(ff)==3};_16["dj_"+_15]=true;var _17="";for(var clz in _16){if(_16[clz]){_17+=clz+" ";}}_13.className=_10.trim(_13.className+" "+_17);_11(90,function(){if(!_f.isBodyLtr()){var _18="dj_rtl dijitRtl "+_17.replace(/ /g,"-rtl ");_13.className=_10.trim(_13.className+" "+_18+"dj_rtl dijitRtl "+_17.replace(/ /g,"-rtl "));}});return has;});},"dojox/charting/axis2d/Invisible":function(){define(["dojo/_base/lang","dojo/_base/declare","./Base","../scaler/linear","dojox/gfx","dojox/lang/utils","dojox/lang/functional","dojo/string"],function(_19,_1a,_1b,lin,g,du,df,_1c){var _1d=du.merge,_1e=4,_1f=45;return _1a("dojox.charting.axis2d.Invisible",_1b,{defaultParams:{vertical:false,fixUpper:"none",fixLower:"none",natural:false,leftBottom:true,includeZero:false,fixed:true,majorLabels:true,minorTicks:true,minorLabels:true,microTicks:false,rotation:0},optionalParams:{min:0,max:1,from:0,to:1,majorTickStep:4,minorTickStep:2,microTickStep:1,labels:[],labelFunc:null,maxLabelSize:0,maxLabelCharCount:0,trailingSymbol:null},constructor:function(_20,_21){this.opt=_19.clone(this.defaultParams);du.updateWithObject(this.opt,_21);du.updateWithPattern(this.opt,_21,this.optionalParams);},dependOnData:function(){return !("min" in this.opt)||!("max" in this.opt);},clear:function(){delete this.scaler;delete this.ticks;this.dirty=true;return this;},initialized:function(){return "scaler" in this&&!(this.dirty&&this.dependOnData());},setWindow:function(_22,_23){this.scale=_22;this.offset=_23;return this.clear();},getWindowScale:function(){return "scale" in this?this.scale:1;},getWindowOffset:function(){return "offset" in this?this.offset:0;},_groupLabelWidth:function(_24,_25,_26){if(!_24.length){return 0;}if(_19.isObject(_24[0])){_24=df.map(_24,function(_27){return _27.text;});}if(_26){_24=df.map(_24,function(_28){return _19.trim(_28).length==0?"":_28.substring(0,_26)+this.trailingSymbol;},this);}var s=_24.join("<br>");return g._base._getTextBox(s,{font:_25}).w||0;},calculate:function(min,max,_29,_2a){if(this.initialized()){return this;}var o=this.opt;this.labels="labels" in o?o.labels:_2a;this.scaler=lin.buildScaler(min,max,_29,o);var tsb=this.scaler.bounds;if("scale" in this){o.from=tsb.lower+this.offset;o.to=(tsb.upper-tsb.lower)/this.scale+o.from;if(!isFinite(o.from)||isNaN(o.from)||!isFinite(o.to)||isNaN(o.to)||o.to-o.from>=tsb.upper-tsb.lower){delete o.from;delete o.to;delete this.scale;delete this.offset;}else{if(o.from<tsb.lower){o.to+=tsb.lower-o.from;o.from=tsb.lower;}else{if(o.to>tsb.upper){o.from+=tsb.upper-o.to;o.to=tsb.upper;}}this.offset=o.from-tsb.lower;}this.scaler=lin.buildScaler(min,max,_29,o);tsb=this.scaler.bounds;if(this.scale==1&&this.offset==0){delete this.scale;delete this.offset;}}var ta=this.chart.theme.axis,_2b=0,_2c=o.rotation%360,_2d=o.font||(ta.majorTick&&ta.majorTick.font)||(ta.tick&&ta.tick.font),_2e=_2d?g.normalizedLength(g.splitFontString(_2d).size):0,_2f=Math.abs(Math.cos(_2c*Math.PI/180)),_30=Math.abs(Math.sin(_2c*Math.PI/180));if(_2c<0){_2c+=360;}if(_2e){if(this.vertical?_2c!=0&&_2c!=180:_2c!=90&&_2c!=270){if(this.labels){_2b=this._groupLabelWidth(this.labels,_2d,o.maxLabelCharCount);}else{var _31=Math.ceil(Math.log(Math.max(Math.abs(tsb.from),Math.abs(tsb.to)))/Math.LN10),t=[];if(tsb.from<0||tsb.to<0){t.push("-");}t.push(_1c.rep("9",_31));var _32=Math.floor(Math.log(tsb.to-tsb.from)/Math.LN10);if(_32>0){t.push(".");t.push(_1c.rep("9",_32));}_2b=g._base._getTextBox(t.join(""),{font:_2d}).w;}_2b=o.maxLabelSize?Math.min(o.maxLabelSize,_2b):_2b;}else{_2b=_2e;}switch(_2c){case 0:case 90:case 180:case 270:break;default:var _33=Math.sqrt(_2b*_2b+_2e*_2e),_34=this.vertical?_2e*_2f+_2b*_30:_2b*_2f+_2e*_30;_2b=Math.min(_33,_34);break;}}this.scaler.minMinorStep=_2b+_1e;this.ticks=lin.buildTicks(this.scaler,o);return this;},getScaler:function(){return this.scaler;},getTicks:function(){return this.ticks;}});});},"dojox/lang/utils":function(){define("dojox/lang/utils",["..","dojo/_base/lang"],function(_35,_36){var du=_36.getObject("lang.utils",true,_35);var _37={},_38=Object.prototype.toString;var _39=function(o){if(o){switch(_38.call(o)){case "[object Array]":return o.slice(0);case "[object Object]":return _36.delegate(o);}}return o;};_36.mixin(du,{coerceType:function(_3a,_3b){switch(typeof _3a){case "number":return Number(eval("("+_3b+")"));case "string":return String(_3b);case "boolean":return Boolean(eval("("+_3b+")"));}return eval("("+_3b+")");},updateWithObject:function(_3c,_3d,_3e){if(!_3d){return _3c;}for(var x in _3c){if(x in _3d&&!(x in _37)){var t=_3c[x];if(t&&typeof t=="object"){du.updateWithObject(t,_3d[x],_3e);}else{_3c[x]=_3e?du.coerceType(t,_3d[x]):_39(_3d[x]);}}}return _3c;},updateWithPattern:function(_3f,_40,_41,_42){if(!_40||!_41){return _3f;}for(var x in _41){if(x in _40&&!(x in _37)){_3f[x]=_42?du.coerceType(_41[x],_40[x]):_39(_40[x]);}}return _3f;},merge:function(_43,_44){if(_44){var _45=_38.call(_43),_46=_38.call(_44),t,i,l,m;switch(_46){case "[object Array]":if(_46==_45){t=new Array(Math.max(_43.length,_44.length));for(i=0,l=t.length;i<l;++i){t[i]=du.merge(_43[i],_44[i]);}return t;}return _44.slice(0);case "[object Object]":if(_46==_45&&_43){t=_36.delegate(_43);for(i in _44){if(i in _43){l=_43[i];m=_44[i];if(m!==l){t[i]=du.merge(l,m);}}else{t[i]=_36.clone(_44[i]);}}return t;}return _36.clone(_44);}}return _44;}});return du;});},"dojox/charting/plot2d/Pie":function(){define("dojox/charting/plot2d/Pie",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","../Element","./_PlotEvents","./common","../axis2d/common","dojox/gfx","dojox/gfx/matrix","dojox/lang/functional","dojox/lang/utils"],function(_47,arr,_48,_49,_4a,dc,da,g,m,df,du){var _4b=0.2;return _48("dojox.charting.plot2d.Pie",[_49,_4a],{defaultParams:{labels:true,ticks:false,fixed:true,precision:1,labelOffset:20,labelStyle:"default",htmlLabels:true,radGrad:"native",fanSize:5,startAngle:0},optionalParams:{radius:0,stroke:{},outline:{},shadow:{},fill:{},font:"",fontColor:"",labelWiring:{}},constructor:function(_4c,_4d){this.opt=_47.clone(this.defaultParams);du.updateWithObject(this.opt,_4d);du.updateWithPattern(this.opt,_4d,this.optionalParams);this.run=null;this.dyn=[];},clear:function(){this.dirty=true;this.dyn=[];this.run=null;return this;},setAxis:function(_4e){return this;},addSeries:function(run){this.run=run;return this;},getSeriesStats:function(){return _47.delegate(dc.defaultStats);},initializeScalers:function(){return this;},getRequiredColors:function(){return this.run?this.run.data.length:0;},render:function(dim,_4f){if(!this.dirty){return this;}this.resetEvents();this.dirty=false;this._eventSeries={};this.cleanGroup();var s=this.group,t=this.chart.theme;if(!this.run||!this.run.data.length){return this;}var rx=(dim.width-_4f.l-_4f.r)/2,ry=(dim.height-_4f.t-_4f.b)/2,r=Math.min(rx,ry),_50="font" in this.opt?this.opt.font:t.axis.font,_51=_50?g.normalizedLength(g.splitFontString(_50).size):0,_52="fontColor" in this.opt?this.opt.fontColor:t.axis.fontColor,_53=m._degToRad(this.opt.startAngle),_54=_53,_55,_56,_57,_58,_59,_5a,run=this.run.data,_5b=this.events();if(typeof run[0]=="number"){_56=df.map(run,"x ? Math.max(x, 0) : 0");if(df.every(_56,"<= 0")){return this;}_57=df.map(_56,"/this",df.foldl(_56,"+",0));if(this.opt.labels){_58=arr.map(_57,function(x){return x>0?this._getLabel(x*100)+"%":"";},this);}}else{_56=df.map(run,"x ? Math.max(x.y, 0) : 0");if(df.every(_56,"<= 0")){return this;}_57=df.map(_56,"/this",df.foldl(_56,"+",0));if(this.opt.labels){_58=arr.map(_57,function(x,i){if(x<=0){return "";}var v=run[i];return "text" in v?v.text:this._getLabel(x*100)+"%";},this);}}var _5c=df.map(run,function(v,i){if(v===null||typeof v=="number"){return t.next("slice",[this.opt,this.run],true);}return t.next("slice",[this.opt,this.run,v],true);},this);if(this.opt.labels){_59=df.foldl1(df.map(_58,function(_5d,i){var _5e=_5c[i].series.font;return g._base._getTextBox(_5d,{font:_5e}).w;},this),"Math.max(a, b)")/2;if(this.opt.labelOffset<0){r=Math.min(rx-2*_59,ry-_51)+this.opt.labelOffset;}_5a=r-this.opt.labelOffset;}if("radius" in this.opt){r=this.opt.radius;_5a=r-this.opt.labelOffset;}var _5f={cx:_4f.l+rx,cy:_4f.t+ry,r:r};this.dyn=[];var _60=new Array(_57.length);arr.some(_57,function(_61,i){if(_61<0){return false;}if(_61==0){this.dyn.push({fill:null,stroke:null});return false;}var v=run[i],_62=_5c[i],_63;if(_61>=1){_63=this._plotFill(_62.series.fill,dim,_4f);_63=this._shapeFill(_63,{x:_5f.cx-_5f.r,y:_5f.cy-_5f.r,width:2*_5f.r,height:2*_5f.r});_63=this._pseudoRadialFill(_63,{x:_5f.cx,y:_5f.cy},_5f.r);var _64=s.createCircle(_5f).setFill(_63).setStroke(_62.series.stroke);this.dyn.push({fill:_63,stroke:_62.series.stroke});if(_5b){var o={element:"slice",index:i,run:this.run,shape:_64,x:i,y:typeof v=="number"?v:v.y,cx:_5f.cx,cy:_5f.cy,cr:r};this._connectEvents(o);_60[i]=o;}return true;}var end=_54+_61*2*Math.PI;if(i+1==_57.length){end=_53+2*Math.PI;}var _65=end-_54,x1=_5f.cx+r*Math.cos(_54),y1=_5f.cy+r*Math.sin(_54),x2=_5f.cx+r*Math.cos(end),y2=_5f.cy+r*Math.sin(end);var _66=m._degToRad(this.opt.fanSize);if(_62.series.fill&&_62.series.fill.type==="radial"&&this.opt.radGrad==="fan"&&_65>_66){var _67=s.createGroup(),_68=Math.ceil(_65/_66),_69=_65/_68;_63=this._shapeFill(_62.series.fill,{x:_5f.cx-_5f.r,y:_5f.cy-_5f.r,width:2*_5f.r,height:2*_5f.r});for(var j=0;j<_68;++j){var _6a=j==0?x1:_5f.cx+r*Math.cos(_54+(j-_4b)*_69),_6b=j==0?y1:_5f.cy+r*Math.sin(_54+(j-_4b)*_69),_6c=j==_68-1?x2:_5f.cx+r*Math.cos(_54+(j+1+_4b)*_69),_6d=j==_68-1?y2:_5f.cy+r*Math.sin(_54+(j+1+_4b)*_69),fan=_67.createPath().moveTo(_5f.cx,_5f.cy).lineTo(_6a,_6b).arcTo(r,r,0,_69>Math.PI,true,_6c,_6d).lineTo(_5f.cx,_5f.cy).closePath().setFill(this._pseudoRadialFill(_63,{x:_5f.cx,y:_5f.cy},r,_54+(j+0.5)*_69,_54+(j+0.5)*_69));}_67.createPath().moveTo(_5f.cx,_5f.cy).lineTo(x1,y1).arcTo(r,r,0,_65>Math.PI,true,x2,y2).lineTo(_5f.cx,_5f.cy).closePath().setStroke(_62.series.stroke);_64=_67;}else{_64=s.createPath().moveTo(_5f.cx,_5f.cy).lineTo(x1,y1).arcTo(r,r,0,_65>Math.PI,true,x2,y2).lineTo(_5f.cx,_5f.cy).closePath().setStroke(_62.series.stroke);var _63=_62.series.fill;if(_63&&_63.type==="radial"){_63=this._shapeFill(_63,{x:_5f.cx-_5f.r,y:_5f.cy-_5f.r,width:2*_5f.r,height:2*_5f.r});if(this.opt.radGrad==="linear"){_63=this._pseudoRadialFill(_63,{x:_5f.cx,y:_5f.cy},r,_54,end);}}else{if(_63&&_63.type==="linear"){_63=this._plotFill(_63,dim,_4f);_63=this._shapeFill(_63,_64.getBoundingBox());}}_64.setFill(_63);}this.dyn.push({fill:_63,stroke:_62.series.stroke});if(_5b){var o={element:"slice",index:i,run:this.run,shape:_64,x:i,y:typeof v=="number"?v:v.y,cx:_5f.cx,cy:_5f.cy,cr:r};this._connectEvents(o);_60[i]=o;}_54=end;return false;},this);if(this.opt.labels){if(this.opt.labelStyle=="default"){_54=_53;arr.some(_57,function(_6e,i){if(_6e<=0){return false;}var _6f=_5c[i];if(_6e>=1){var v=run[i],_70=da.createText[this.opt.htmlLabels&&g.renderer!="vml"?"html":"gfx"](this.chart,s,_5f.cx,_5f.cy+_51/2,"middle",_58[i],_6f.series.font,_6f.series.fontColor);if(this.opt.htmlLabels){this.htmlElements.push(_70);}return true;}var end=_54+_6e*2*Math.PI,v=run[i];if(i+1==_57.length){end=_53+2*Math.PI;}var _71=(_54+end)/2,x=_5f.cx+_5a*Math.cos(_71),y=_5f.cy+_5a*Math.sin(_71)+_51/2;var _70=da.createText[this.opt.htmlLabels&&g.renderer!="vml"?"html":"gfx"](this.chart,s,x,y,"middle",_58[i],_6f.series.font,_6f.series.fontColor);if(this.opt.htmlLabels){this.htmlElements.push(_70);}_54=end;return false;},this);}else{if(this.opt.labelStyle=="columns"){_54=_53;var _72=[];arr.forEach(_57,function(_73,i){var end=_54+_73*2*Math.PI;if(i+1==_57.length){end=_53+2*Math.PI;}var _74=(_54+end)/2;_72.push({angle:_74,left:Math.cos(_74)<0,theme:_5c[i],index:i,omit:end-_54<0.001});_54=end;});var _75=g._base._getTextBox("a",{font:_50}).h;this._getProperLabelRadius(_72,_75,_5f.r*1.1);arr.forEach(_72,function(_76,i){if(!_76.omit){var _77=_5f.cx-_5f.r*2,_78=_5f.cx+_5f.r*2,_79=g._base._getTextBox(_58[i],{font:_50}).w,x=_5f.cx+_76.labelR*Math.cos(_76.angle),y=_5f.cy+_76.labelR*Math.sin(_76.angle),_7a=(_76.left)?(_77+_79):(_78-_79),_7b=(_76.left)?_77:_7a;var _7c=s.createPath().moveTo(_5f.cx+_5f.r*Math.cos(_76.angle),_5f.cy+_5f.r*Math.sin(_76.angle));if(Math.abs(_76.labelR*Math.cos(_76.angle))<_5f.r*2-_79){_7c.lineTo(x,y);}_7c.lineTo(_7a,y).setStroke(_76.theme.series.labelWiring);var _7d=da.createText[this.opt.htmlLabels&&g.renderer!="vml"?"html":"gfx"](this.chart,s,_7b,y,"left",_58[i],_76.theme.series.font,_76.theme.series.fontColor);if(this.opt.htmlLabels){this.htmlElements.push(_7d);}}},this);}}}var esi=0;this._eventSeries[this.run.name]=df.map(run,function(v){return v<=0?null:_60[esi++];});return this;},_getProperLabelRadius:function(_7e,_7f,_80){var _81={},_82={},_83=1,_84=1;if(_7e.length==1){_7e[0].labelR=_80;return;}for(var i=0;i<_7e.length;i++){var _85=Math.abs(Math.sin(_7e[i].angle));if(_7e[i].left){if(_83>_85){_83=_85;_81=_7e[i];}}else{if(_84>_85){_84=_85;_82=_7e[i];}}}_81.labelR=_82.labelR=_80;this._calculateLabelR(_81,_7e,_7f);this._calculateLabelR(_82,_7e,_7f);},_calculateLabelR:function(_86,_87,_88){var i=_86.index,_89=_87.length,_8a=_86.labelR;while(!(_87[i%_89].left^_87[(i+1)%_89].left)){if(!_87[(i+1)%_89].omit){var _8b=(Math.sin(_87[i%_89].angle)*_8a+((_87[i%_89].left)?(-_88):_88))/Math.sin(_87[(i+1)%_89].angle);_8a=(_8b<_86.labelR)?_86.labelR:_8b;_87[(i+1)%_89].labelR=_8a;}i++;}i=_86.index;var j=(i==0)?_89-1:i-1;while(!(_87[i].left^_87[j].left)){if(!_87[j].omit){var _8b=(Math.sin(_87[i].angle)*_8a+((_87[i].left)?_88:(-_88)))/Math.sin(_87[j].angle);_8a=(_8b<_86.labelR)?_86.labelR:_8b;_87[j].labelR=_8a;}i--;j--;i=(i<0)?i+_87.length:i;j=(j<0)?j+_87.length:j;}},_getLabel:function(_8c){return dc.getLabel(_8c,this.opt.fixed,this.opt.precision);}});});},"dijit/hccss":function(){define("dijit/hccss",["require","dojo/_base/config","dojo/dom-class","dojo/dom-construct","dojo/dom-style","dojo/ready","dojo/_base/sniff","dojo/_base/window"],function(_8d,_8e,_8f,_90,_91,_92,has,win){if(has("ie")||has("mozilla")){_92(90,function(){var div=_90.create("div",{id:"a11yTestNode",style:{cssText:"border: 1px solid;"+"border-color:red green;"+"position: absolute;"+"height: 5px;"+"top: -999px;"+"background-image: url(\""+(_8e.blankGif||_8d.toUrl("dojo/resources/blank.gif"))+"\");"}},win.body());var cs=_91.getComputedStyle(div);if(cs){var _93=cs.backgroundImage;var _94=(cs.borderTopColor==cs.borderRightColor)||(_93!=null&&(_93=="none"||_93=="url(invalid-url:)"));if(_94){_8f.add(win.body(),"dijit_a11y");}if(has("ie")){div.outerHTML="";}else{win.body().removeChild(div);}}});}});},"dojox/charting/action2d/Shake":function(){define("dojox/charting/action2d/Shake",["dojo/_base/connect","dojo/_base/declare","./PlotAction","dojo/fx","dojo/fx/easing","dojox/gfx/matrix","dojox/gfx/fx"],function(hub,_95,_96,df,dfe,m,gf){var _97=3;return _95("dojox.charting.action2d.Shake",_96,{defaultParams:{duration:400,easing:dfe.backOut,shiftX:_97,shiftY:_97},optionalParams:{},constructor:function(_98,_99,_9a){if(!_9a){_9a={};}this.shiftX=typeof _9a.shiftX=="number"?_9a.shiftX:_97;this.shiftY=typeof _9a.shiftY=="number"?_9a.shiftY:_97;this.connect();},process:function(o){if(!o.shape||!(o.type in this.overOutEvents)){return;}var _9b=o.run.name,_9c=o.index,_9d=[],_9e,_9f=o.type=="onmouseover"?this.shiftX:-this.shiftX,_a0=o.type=="onmouseover"?this.shiftY:-this.shiftY;if(_9b in this.anim){_9e=this.anim[_9b][_9c];}else{this.anim[_9b]={};}if(_9e){_9e.action.stop(true);}else{this.anim[_9b][_9c]=_9e={};}var _a1={shape:o.shape,duration:this.duration,easing:this.easing,transform:[{name:"translate",start:[this.shiftX,this.shiftY],end:[0,0]},m.identity]};if(o.shape){_9d.push(gf.animateTransform(_a1));}if(o.oultine){_a1.shape=o.outline;_9d.push(gf.animateTransform(_a1));}if(o.shadow){_a1.shape=o.shadow;_9d.push(gf.animateTransform(_a1));}if(!_9d.length){delete this.anim[_9b][_9c];return;}_9e.action=df.combine(_9d);if(o.type=="onmouseout"){hub.connect(_9e.action,"onEnd",this,function(){if(this.anim[_9b]){delete this.anim[_9b][_9c];}});}_9e.action.play();}});});},"dojox/lang/functional/lambda":function(){define("dojox/lang/functional/lambda",["../..","dojo/_base/kernel","dojo/_base/lang","dojo/_base/array"],function(_a2,_a3,_a4,arr){var df=_a4.getObject("lang.functional",true,_a2);var _a5={};var _a6="ab".split(/a*/).length>1?String.prototype.split:function(sep){var r=this.split.call(this,sep),m=sep.exec(this);if(m&&m.index==0){r.unshift("");}return r;};var _a7=function(s){var _a8=[],_a9=_a6.call(s,/\s*->\s*/m);if(_a9.length>1){while(_a9.length){s=_a9.pop();_a8=_a9.pop().split(/\s*,\s*|\s+/m);if(_a9.length){_a9.push("(function("+_a8+"){return ("+s+")})");}}}else{if(s.match(/\b_\b/)){_a8=["_"];}else{var l=s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m),r=s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m);if(l||r){if(l){_a8.push("$1");s="$1"+s;}if(r){_a8.push("$2");s=s+"$2";}}else{var _aa=s.replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|dojo|dijit|dojox|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g,"").match(/([a-z_$][a-z_$\d]*)/gi)||[],t={};arr.forEach(_aa,function(v){if(!(v in t)){_a8.push(v);t[v]=1;}});}}}return {args:_a8,body:s};};var _ab=function(a){return a.length?function(){var i=a.length-1,x=df.lambda(a[i]).apply(this,arguments);for(--i;i>=0;--i){x=df.lambda(a[i]).call(this,x);}return x;}:function(x){return x;};};_a4.mixin(df,{rawLambda:function(s){return _a7(s);},buildLambda:function(s){s=_a7(s);return "function("+s.args.join(",")+"){return ("+s.body+");}";},lambda:function(s){if(typeof s=="function"){return s;}if(s instanceof Array){return _ab(s);}if(s in _a5){return _a5[s];}s=_a7(s);return _a5[s]=new Function(s.args,"return ("+s.body+");");},clearLambdaCache:function(){_a5={};}});return df;});},"dojox/lang/functional/reversed":function(){define(["dojo/_base/lang","dojo/_base/window","./lambda"],function(_ac,win,df){_ac.mixin(df,{filterRev:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var t=[],v,i=a.length-1;for(;i>=0;--i){v=a[i];if(f.call(o,v,i,a)){t.push(v);}}return t;},forEachRev:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);for(var i=a.length-1;i>=0;f.call(o,a[i],i,a),--i){}},mapRev:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var n=a.length,t=new Array(n),i=n-1,j=0;for(;i>=0;t[j++]=f.call(o,a[i],i,a),--i){}return t;},everyRev:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);for(var i=a.length-1;i>=0;--i){if(!f.call(o,a[i],i,a)){return false;}}return true;},someRev:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);for(var i=a.length-1;i>=0;--i){if(f.call(o,a[i],i,a)){return true;}}return false;}});return df;});},"dojox/charting/scaler/primitive":function(){define("dojox/charting/scaler/primitive",["dojo/_base/lang"],function(_ad){var _ae=_ad.getObject("dojox.charting.scaler.primitive",true);return _ad.mixin(_ae,{buildScaler:function(min,max,_af,_b0){if(min==max){min-=0.5;max+=0.5;}return {bounds:{lower:min,upper:max,from:min,to:max,scale:_af/(max-min),span:_af},scaler:_ae};},buildTicks:function(_b1,_b2){return {major:[],minor:[],micro:[]};},getTransformerFromModel:function(_b3){var _b4=_b3.bounds.from,_b5=_b3.bounds.scale;return function(x){return (x-_b4)*_b5;};},getTransformerFromPlot:function(_b6){var _b7=_b6.bounds.from,_b8=_b6.bounds.scale;return function(x){return x/_b8+_b7;};}});});},"dojox/charting/plot2d/Candlesticks":function(){define("dojox/charting/plot2d/Candlesticks",["dojo/_base/lang","dojo/_base/declare","dojo/_base/array","./Base","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils","dojox/gfx/fx"],function(_b9,_ba,arr,_bb,dc,df,dfr,du,fx){var _bc=dfr.lambda("item.purgeGroup()");return _ba("dojox.charting.plot2d.Candlesticks",_bb,{defaultParams:{hAxis:"x",vAxis:"y",gap:2,animate:null},optionalParams:{minBarSize:1,maxBarSize:1,stroke:{},outline:{},shadow:{},fill:{},font:"",fontColor:""},constructor:function(_bd,_be){this.opt=_b9.clone(this.defaultParams);du.updateWithObject(this.opt,_be);du.updateWithPattern(this.opt,_be,this.optionalParams);this.series=[];this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.animate=this.opt.animate;},collectStats:function(_bf){var _c0=_b9.delegate(dc.defaultStats);for(var i=0;i<_bf.length;i++){var run=_bf[i];if(!run.data.length){continue;}var _c1=_c0.vmin,_c2=_c0.vmax;if(!("ymin" in run)||!("ymax" in run)){arr.forEach(run.data,function(val,idx){if(val!==null){var x=val.x||idx+1;_c0.hmin=Math.min(_c0.hmin,x);_c0.hmax=Math.max(_c0.hmax,x);_c0.vmin=Math.min(_c0.vmin,val.open,val.close,val.high,val.low);_c0.vmax=Math.max(_c0.vmax,val.open,val.close,val.high,val.low);}});}if("ymin" in run){_c0.vmin=Math.min(_c1,run.ymin);}if("ymax" in run){_c0.vmax=Math.max(_c2,run.ymax);}}return _c0;},getSeriesStats:function(){var _c3=this.collectStats(this.series);_c3.hmin-=0.5;_c3.hmax+=0.5;return _c3;},render:function(dim,_c4){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_c4);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_bc);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(_c5){_c5.cleanGroup(s);});}var t=this.chart.theme,f,gap,_c6,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_c7=Math.max(0,this._vScaler.bounds.lower),_c8=vt(_c7),_c9=this.events();f=dc.calculateBarSize(this._hScaler.bounds.scale,this.opt);gap=f.gap;_c6=f.size;for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();var _ca=t.next("candlestick",[this.opt,run]),s=run.group,_cb=new Array(run.data.length);for(var j=0;j<run.data.length;++j){var v=run.data[j];if(v!==null){var _cc=t.addMixin(_ca,"candlestick",v,true);var x=ht(v.x||(j+0.5))+_c4.l+gap,y=dim.height-_c4.b,_cd=vt(v.open),_ce=vt(v.close),_cf=vt(v.high),low=vt(v.low);if("mid" in v){var mid=vt(v.mid);}if(low>_cf){var tmp=_cf;_cf=low;low=tmp;}if(_c6>=1){var _d0=_cd>_ce;var _d1={x1:_c6/2,x2:_c6/2,y1:y-_cf,y2:y-low},_d2={x:0,y:y-Math.max(_cd,_ce),width:_c6,height:Math.max(_d0?_cd-_ce:_ce-_cd,1)};var _d3=s.createGroup();_d3.setTransform({dx:x,dy:0});var _d4=_d3.createGroup();_d4.createLine(_d1).setStroke(_cc.series.stroke);_d4.createRect(_d2).setStroke(_cc.series.stroke).setFill(_d0?_cc.series.fill:"white");if("mid" in v){_d4.createLine({x1:(_cc.series.stroke.width||1),x2:_c6-(_cc.series.stroke.width||1),y1:y-mid,y2:y-mid}).setStroke(_d0?"white":_cc.series.stroke);}run.dyn.fill=_cc.series.fill;run.dyn.stroke=_cc.series.stroke;if(_c9){var o={element:"candlestick",index:j,run:run,shape:_d4,x:x,y:y-Math.max(_cd,_ce),cx:_c6/2,cy:(y-Math.max(_cd,_ce))+(Math.max(_d0?_cd-_ce:_ce-_cd,1)/2),width:_c6,height:Math.max(_d0?_cd-_ce:_ce-_cd,1),data:v};this._connectEvents(o);_cb[j]=o;}}if(this.animate){this._animateCandlesticks(_d3,y-low,_cf-low);}}}this._eventSeries[run.name]=_cb;run.dirty=false;}this.dirty=false;return this;},_animateCandlesticks:function(_d5,_d6,_d7){fx.animateTransform(_b9.delegate({shape:_d5,duration:1200,transform:[{name:"translate",start:[0,_d6-(_d6/_d7)],end:[0,0]},{name:"scale",start:[1,1/_d7],end:[1,1]},{name:"original"}]},this.animate)).play();}});});},"dojox/charting/widget/Sparkline":function(){define("dojox/charting/widget/Sparkline",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","dojo/_base/html","dojo/query","./Chart","../themes/GreySkies","../plot2d/Lines","dojo/dom-prop"],function(_d8,_d9,_da,_db,_dc,_dd,_de,_df,_e0){_da("dojox.charting.widget.Sparkline",_dd,{theme:_de,margins:{l:0,r:0,t:0,b:0},type:"Lines",valueFn:"Number(x)",store:"",field:"",query:"",queryOptions:"",start:"0",count:"Infinity",sort:"",data:"",name:"default",buildRendering:function(){var n=this.srcNodeRef;if(!n.childNodes.length||!_dc("> .axis, > .plot, > .action, > .series",n).length){var _e1=document.createElement("div");_e0.set(_e1,{"class":"plot","name":"default","type":this.type});n.appendChild(_e1);var _e2=document.createElement("div");_e0.set(_e2,{"class":"series",plot:"default",name:this.name,start:this.start,count:this.count,valueFn:this.valueFn});_d9.forEach(["store","field","query","queryOptions","sort","data"],function(i){if(this[i].length){_e0.set(_e2,i,this[i]);}},this);n.appendChild(_e2);}this.inherited(arguments);}});});},"dojox/gfx/matrix":function(){define("dojox/gfx/matrix",["./_base","dojo/_base/lang"],function(g,_e3){var m=g.matrix={};var _e4={};m._degToRad=function(_e5){return _e4[_e5]||(_e4[_e5]=(Math.PI*_e5/180));};m._radToDeg=function(_e6){return _e6/Math.PI*180;};m.Matrix2D=function(arg){if(arg){if(typeof arg=="number"){this.xx=this.yy=arg;}else{if(arg instanceof Array){if(arg.length>0){var _e7=m.normalize(arg[0]);for(var i=1;i<arg.length;++i){var l=_e7,r=m.normalize(arg[i]);_e7=new m.Matrix2D();_e7.xx=l.xx*r.xx+l.xy*r.yx;_e7.xy=l.xx*r.xy+l.xy*r.yy;_e7.yx=l.yx*r.xx+l.yy*r.yx;_e7.yy=l.yx*r.xy+l.yy*r.yy;_e7.dx=l.xx*r.dx+l.xy*r.dy+l.dx;_e7.dy=l.yx*r.dx+l.yy*r.dy+l.dy;}_e3.mixin(this,_e7);}}else{_e3.mixin(this,arg);}}}};_e3.extend(m.Matrix2D,{xx:1,xy:0,yx:0,yy:1,dx:0,dy:0});_e3.mixin(m,{identity:new m.Matrix2D(),flipX:new m.Matrix2D({xx:-1}),flipY:new m.Matrix2D({yy:-1}),flipXY:new m.Matrix2D({xx:-1,yy:-1}),translate:function(a,b){if(arguments.length>1){return new m.Matrix2D({dx:a,dy:b});}return new m.Matrix2D({dx:a.x,dy:a.y});},scale:function(a,b){if(arguments.length>1){return new m.Matrix2D({xx:a,yy:b});}if(typeof a=="number"){return new m.Matrix2D({xx:a,yy:a});}return new m.Matrix2D({xx:a.x,yy:a.y});},rotate:function(_e8){var c=Math.cos(_e8);var s=Math.sin(_e8);return new m.Matrix2D({xx:c,xy:-s,yx:s,yy:c});},rotateg:function(_e9){return m.rotate(m._degToRad(_e9));},skewX:function(_ea){return new m.Matrix2D({xy:Math.tan(_ea)});},skewXg:function(_eb){return m.skewX(m._degToRad(_eb));},skewY:function(_ec){return new m.Matrix2D({yx:Math.tan(_ec)});},skewYg:function(_ed){return m.skewY(m._degToRad(_ed));},reflect:function(a,b){if(arguments.length==1){b=a.y;a=a.x;}var a2=a*a,b2=b*b,n2=a2+b2,xy=2*a*b/n2;return new m.Matrix2D({xx:2*a2/n2-1,xy:xy,yx:xy,yy:2*b2/n2-1});},project:function(a,b){if(arguments.length==1){b=a.y;a=a.x;}var a2=a*a,b2=b*b,n2=a2+b2,xy=a*b/n2;return new m.Matrix2D({xx:a2/n2,xy:xy,yx:xy,yy:b2/n2});},normalize:function(_ee){return (_ee instanceof m.Matrix2D)?_ee:new m.Matrix2D(_ee);},clone:function(_ef){var obj=new m.Matrix2D();for(var i in _ef){if(typeof (_ef[i])=="number"&&typeof (obj[i])=="number"&&obj[i]!=_ef[i]){obj[i]=_ef[i];}}return obj;},invert:function(_f0){var M=m.normalize(_f0),D=M.xx*M.yy-M.xy*M.yx;M=new m.Matrix2D({xx:M.yy/D,xy:-M.xy/D,yx:-M.yx/D,yy:M.xx/D,dx:(M.xy*M.dy-M.yy*M.dx)/D,dy:(M.yx*M.dx-M.xx*M.dy)/D});return M;},_multiplyPoint:function(_f1,x,y){return {x:_f1.xx*x+_f1.xy*y+_f1.dx,y:_f1.yx*x+_f1.yy*y+_f1.dy};},multiplyPoint:function(_f2,a,b){var M=m.normalize(_f2);if(typeof a=="number"&&typeof b=="number"){return m._multiplyPoint(M,a,b);}return m._multiplyPoint(M,a.x,a.y);},multiply:function(_f3){var M=m.normalize(_f3);for(var i=1;i<arguments.length;++i){var l=M,r=m.normalize(arguments[i]);M=new m.Matrix2D();M.xx=l.xx*r.xx+l.xy*r.yx;M.xy=l.xx*r.xy+l.xy*r.yy;M.yx=l.yx*r.xx+l.yy*r.yx;M.yy=l.yx*r.xy+l.yy*r.yy;M.dx=l.xx*r.dx+l.xy*r.dy+l.dx;M.dy=l.yx*r.dx+l.yy*r.dy+l.dy;}return M;},_sandwich:function(_f4,x,y){return m.multiply(m.translate(x,y),_f4,m.translate(-x,-y));},scaleAt:function(a,b,c,d){switch(arguments.length){case 4:return m._sandwich(m.scale(a,b),c,d);case 3:if(typeof c=="number"){return m._sandwich(m.scale(a),b,c);}return m._sandwich(m.scale(a,b),c.x,c.y);}return m._sandwich(m.scale(a),b.x,b.y);},rotateAt:function(_f5,a,b){if(arguments.length>2){return m._sandwich(m.rotate(_f5),a,b);}return m._sandwich(m.rotate(_f5),a.x,a.y);},rotategAt:function(_f6,a,b){if(arguments.length>2){return m._sandwich(m.rotateg(_f6),a,b);}return m._sandwich(m.rotateg(_f6),a.x,a.y);},skewXAt:function(_f7,a,b){if(arguments.length>2){return m._sandwich(m.skewX(_f7),a,b);}return m._sandwich(m.skewX(_f7),a.x,a.y);},skewXgAt:function(_f8,a,b){if(arguments.length>2){return m._sandwich(m.skewXg(_f8),a,b);}return m._sandwich(m.skewXg(_f8),a.x,a.y);},skewYAt:function(_f9,a,b){if(arguments.length>2){return m._sandwich(m.skewY(_f9),a,b);}return m._sandwich(m.skewY(_f9),a.x,a.y);},skewYgAt:function(_fa,a,b){if(arguments.length>2){return m._sandwich(m.skewYg(_fa),a,b);}return m._sandwich(m.skewYg(_fa),a.x,a.y);}});g.Matrix2D=m.Matrix2D;return m;});},"dojox/charting/plot2d/Scatter":function(){define("dojox/charting/plot2d/Scatter",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","./Base","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils","dojox/gfx/fx","dojox/gfx/gradutils"],function(_fb,arr,_fc,_fd,dc,df,dfr,du,fx,_fe){var _ff=dfr.lambda("item.purgeGroup()");return _fc("dojox.charting.plot2d.Scatter",_fd,{defaultParams:{hAxis:"x",vAxis:"y",shadows:null,animate:null},optionalParams:{markerStroke:{},markerOutline:{},markerShadow:{},markerFill:{},markerFont:"",markerFontColor:""},constructor:function(_100,_101){this.opt=_fb.clone(this.defaultParams);du.updateWithObject(this.opt,_101);du.updateWithPattern(this.opt,_101,this.optionalParams);this.series=[];this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.animate=this.opt.animate;},render:function(dim,_102){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_102);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_ff);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,_103=this.events();for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();if(!run.data.length){run.dirty=false;t.skip();continue;}var _104=t.next("marker",[this.opt,run]),s=run.group,_105,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler);if(typeof run.data[0]=="number"){_105=arr.map(run.data,function(v,i){return {x:ht(i+1)+_102.l,y:dim.height-_102.b-vt(v)};},this);}else{_105=arr.map(run.data,function(v,i){return {x:ht(v.x)+_102.l,y:dim.height-_102.b-vt(v.y)};},this);}var _106=new Array(_105.length),_107=new Array(_105.length),_108=new Array(_105.length);arr.forEach(_105,function(c,i){var _109=typeof run.data[i]=="number"?t.post(_104,"marker"):t.addMixin(_104,"marker",run.data[i],true),path="M"+c.x+" "+c.y+" "+_109.symbol;if(_109.marker.shadow){_106[i]=s.createPath("M"+(c.x+_109.marker.shadow.dx)+" "+(c.y+_109.marker.shadow.dy)+" "+_109.symbol).setStroke(_109.marker.shadow).setFill(_109.marker.shadow.color);if(this.animate){this._animateScatter(_106[i],dim.height-_102.b);}}if(_109.marker.outline){var _10a=dc.makeStroke(_109.marker.outline);_10a.width=2*_10a.width+_109.marker.stroke.width;_108[i]=s.createPath(path).setStroke(_10a);if(this.animate){this._animateScatter(_108[i],dim.height-_102.b);}}var _10b=dc.makeStroke(_109.marker.stroke),fill=this._plotFill(_109.marker.fill,dim,_102);if(fill&&(fill.type==="linear"||fill.type=="radial")){var _10c=_fe.getColor(fill,{x:c.x,y:c.y});if(_10b){_10b.color=_10c;}_107[i]=s.createPath(path).setStroke(_10b).setFill(_10c);}else{_107[i]=s.createPath(path).setStroke(_10b).setFill(fill);}if(this.animate){this._animateScatter(_107[i],dim.height-_102.b);}},this);if(_107.length){run.dyn.stroke=_107[_107.length-1].getStroke();run.dyn.fill=_107[_107.length-1].getFill();}if(_103){var _10d=new Array(_107.length);arr.forEach(_107,function(s,i){var o={element:"marker",index:i,run:run,shape:s,outline:_108&&_108[i]||null,shadow:_106&&_106[i]||null,cx:_105[i].x,cy:_105[i].y};if(typeof run.data[0]=="number"){o.x=i+1;o.y=run.data[i];}else{o.x=run.data[i].x;o.y=run.data[i].y;}this._connectEvents(o);_10d[i]=o;},this);this._eventSeries[run.name]=_10d;}else{delete this._eventSeries[run.name];}run.dirty=false;}this.dirty=false;return this;},_animateScatter:function(_10e,_10f){fx.animateTransform(_fb.delegate({shape:_10e,duration:1200,transform:[{name:"translate",start:[0,_10f],end:[0,0]},{name:"scale",start:[0,0],end:[1,1]},{name:"original"}]},this.animate)).play();}});});},"dojox/lang/functional/scan":function(){define("dojox/lang/functional/scan",["dojo/_base/kernel","dojo/_base/lang","./lambda"],function(d,_110,df){var _111={};d.mixin(df,{scanl:function(a,f,z,o){if(typeof a=="string"){a=a.split("");}o=o||d.global;f=df.lambda(f);var t,n,i;if(d.isArray(a)){t=new Array((n=a.length)+1);t[0]=z;for(i=0;i<n;z=f.call(o,z,a[i],i,a),t[++i]=z){}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){t=[z];for(i=0;a.hasNext();t.push(z=f.call(o,z,a.next(),i++,a))){}}else{t=[z];for(i in a){if(!(i in _111)){t.push(z=f.call(o,z,a[i],i,a));}}}}return t;},scanl1:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||d.global;f=df.lambda(f);var t,n,z,_112=true;if(d.isArray(a)){t=new Array(n=a.length);t[0]=z=a[0];for(var i=1;i<n;t[i]=z=f.call(o,z,a[i],i,a),++i){}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){if(a.hasNext()){t=[z=a.next()];for(i=1;a.hasNext();t.push(z=f.call(o,z,a.next(),i++,a))){}}}else{for(i in a){if(!(i in _111)){if(_112){t=[z=a[i]];_112=false;}else{t.push(z=f.call(o,z,a[i],i,a));}}}}}return t;},scanr:function(a,f,z,o){if(typeof a=="string"){a=a.split("");}o=o||d.global;f=df.lambda(f);var n=a.length,t=new Array(n+1),i=n;t[n]=z;for(;i>0;--i,z=f.call(o,z,a[i],i,a),t[i]=z){}return t;},scanr1:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||d.global;f=df.lambda(f);var n=a.length,t=new Array(n),z=a[n-1],i=n-1;t[i]=z;for(;i>0;--i,z=f.call(o,z,a[i],i,a),t[i]=z){}return t;}});});},"dojox/color/_base":function(){define("dojox/color/_base",["dojo/_base/kernel","../main","dojo/_base/lang","dojo/_base/Color","dojo/colors"],function(dojo,_113,lang,_114,_115){var cx=lang.getObject("dojox.color",true);cx.Color=_114;cx.blend=_114.blendColors;cx.fromRgb=_114.fromRgb;cx.fromHex=_114.fromHex;cx.fromArray=_114.fromArray;cx.fromString=_114.fromString;cx.greyscale=_115.makeGrey;lang.mixin(cx,{fromCmy:function(cyan,_116,_117){if(lang.isArray(cyan)){_116=cyan[1],_117=cyan[2],cyan=cyan[0];}else{if(lang.isObject(cyan)){_116=cyan.m,_117=cyan.y,cyan=cyan.c;}}cyan/=100,_116/=100,_117/=100;var r=1-cyan,g=1-_116,b=1-_117;return new _114({r:Math.round(r*255),g:Math.round(g*255),b:Math.round(b*255)});},fromCmyk:function(cyan,_118,_119,_11a){if(lang.isArray(cyan)){_118=cyan[1],_119=cyan[2],_11a=cyan[3],cyan=cyan[0];}else{if(lang.isObject(cyan)){_118=cyan.m,_119=cyan.y,_11a=cyan.b,cyan=cyan.c;}}cyan/=100,_118/=100,_119/=100,_11a/=100;var r,g,b;r=1-Math.min(1,cyan*(1-_11a)+_11a);g=1-Math.min(1,_118*(1-_11a)+_11a);b=1-Math.min(1,_119*(1-_11a)+_11a);return new _114({r:Math.round(r*255),g:Math.round(g*255),b:Math.round(b*255)});},fromHsl:function(hue,_11b,_11c){if(lang.isArray(hue)){_11b=hue[1],_11c=hue[2],hue=hue[0];}else{if(lang.isObject(hue)){_11b=hue.s,_11c=hue.l,hue=hue.h;}}_11b/=100;_11c/=100;while(hue<0){hue+=360;}while(hue>=360){hue-=360;}var r,g,b;if(hue<120){r=(120-hue)/60,g=hue/60,b=0;}else{if(hue<240){r=0,g=(240-hue)/60,b=(hue-120)/60;}else{r=(hue-240)/60,g=0,b=(360-hue)/60;}}r=2*_11b*Math.min(r,1)+(1-_11b);g=2*_11b*Math.min(g,1)+(1-_11b);b=2*_11b*Math.min(b,1)+(1-_11b);if(_11c<0.5){r*=_11c,g*=_11c,b*=_11c;}else{r=(1-_11c)*r+2*_11c-1;g=(1-_11c)*g+2*_11c-1;b=(1-_11c)*b+2*_11c-1;}return new _114({r:Math.round(r*255),g:Math.round(g*255),b:Math.round(b*255)});}});cx.fromHsv=function(hue,_11d,_11e){if(lang.isArray(hue)){_11d=hue[1],_11e=hue[2],hue=hue[0];}else{if(lang.isObject(hue)){_11d=hue.s,_11e=hue.v,hue=hue.h;}}if(hue==360){hue=0;}_11d/=100;_11e/=100;var r,g,b;if(_11d==0){r=_11e,b=_11e,g=_11e;}else{var _11f=hue/60,i=Math.floor(_11f),f=_11f-i;var p=_11e*(1-_11d);var q=_11e*(1-(_11d*f));var t=_11e*(1-(_11d*(1-f)));switch(i){case 0:r=_11e,g=t,b=p;break;case 1:r=q,g=_11e,b=p;break;case 2:r=p,g=_11e,b=t;break;case 3:r=p,g=q,b=_11e;break;case 4:r=t,g=p,b=_11e;break;case 5:r=_11e,g=p,b=q;break;}}return new _114({r:Math.round(r*255),g:Math.round(g*255),b:Math.round(b*255)});};lang.extend(_114,{toCmy:function(){var cyan=1-(this.r/255),_120=1-(this.g/255),_121=1-(this.b/255);return {c:Math.round(cyan*100),m:Math.round(_120*100),y:Math.round(_121*100)};},toCmyk:function(){var cyan,_122,_123,_124;var r=this.r/255,g=this.g/255,b=this.b/255;_124=Math.min(1-r,1-g,1-b);cyan=(1-r-_124)/(1-_124);_122=(1-g-_124)/(1-_124);_123=(1-b-_124)/(1-_124);return {c:Math.round(cyan*100),m:Math.round(_122*100),y:Math.round(_123*100),b:Math.round(_124*100)};},toHsl:function(){var r=this.r/255,g=this.g/255,b=this.b/255;var min=Math.min(r,b,g),max=Math.max(r,g,b);var _125=max-min;var h=0,s=0,l=(min+max)/2;if(l>0&&l<1){s=_125/((l<0.5)?(2*l):(2-2*l));}if(_125>0){if(max==r&&max!=g){h+=(g-b)/_125;}if(max==g&&max!=b){h+=(2+(b-r)/_125);}if(max==b&&max!=r){h+=(4+(r-g)/_125);}h*=60;}return {h:h,s:Math.round(s*100),l:Math.round(l*100)};},toHsv:function(){var r=this.r/255,g=this.g/255,b=this.b/255;var min=Math.min(r,b,g),max=Math.max(r,g,b);var _126=max-min;var h=null,s=(max==0)?0:(_126/max);if(s==0){h=0;}else{if(r==max){h=60*(g-b)/_126;}else{if(g==max){h=120+60*(b-r)/_126;}else{h=240+60*(r-g)/_126;}}if(h<0){h+=360;}}return {h:h,s:Math.round(s*100),v:Math.round(max*100)};}});return cx;});},"dojox/charting/plot2d/OHLC":function(){define(["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","./Base","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils","dojox/gfx/fx"],function(lang,arr,_127,Base,dc,df,dfr,du,fx){var _128=dfr.lambda("item.purgeGroup()");return _127("dojox.charting.plot2d.OHLC",Base,{defaultParams:{hAxis:"x",vAxis:"y",gap:2,animate:null},optionalParams:{minBarSize:1,maxBarSize:1,stroke:{},outline:{},shadow:{},fill:{},font:"",fontColor:""},constructor:function(_129,_12a){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_12a);du.updateWithPattern(this.opt,_12a,this.optionalParams);this.series=[];this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.animate=this.opt.animate;},collectStats:function(_12b){var _12c=lang.delegate(dc.defaultStats);for(var i=0;i<_12b.length;i++){var run=_12b[i];if(!run.data.length){continue;}var _12d=_12c.vmin,_12e=_12c.vmax;if(!("ymin" in run)||!("ymax" in run)){arr.forEach(run.data,function(val,idx){if(val!==null){var x=val.x||idx+1;_12c.hmin=Math.min(_12c.hmin,x);_12c.hmax=Math.max(_12c.hmax,x);_12c.vmin=Math.min(_12c.vmin,val.open,val.close,val.high,val.low);_12c.vmax=Math.max(_12c.vmax,val.open,val.close,val.high,val.low);}});}if("ymin" in run){_12c.vmin=Math.min(_12d,run.ymin);}if("ymax" in run){_12c.vmax=Math.max(_12e,run.ymax);}}return _12c;},getSeriesStats:function(){var _12f=this.collectStats(this.series);_12f.hmin-=0.5;_12f.hmax+=0.5;return _12f;},render:function(dim,_130){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_130);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_128);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,f,gap,_131,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_132=Math.max(0,this._vScaler.bounds.lower),_133=vt(_132),_134=this.events();f=dc.calculateBarSize(this._hScaler.bounds.scale,this.opt);gap=f.gap;_131=f.size;for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();var _135=t.next("candlestick",[this.opt,run]),s=run.group,_136=new Array(run.data.length);for(var j=0;j<run.data.length;++j){var v=run.data[j];if(v!==null){var _137=t.addMixin(_135,"candlestick",v,true);var x=ht(v.x||(j+0.5))+_130.l+gap,y=dim.height-_130.b,open=vt(v.open),_138=vt(v.close),high=vt(v.high),low=vt(v.low);if(low>high){var tmp=high;high=low;low=tmp;}if(_131>=1){var hl={x1:_131/2,x2:_131/2,y1:y-high,y2:y-low},op={x1:0,x2:((_131/2)+((_137.series.stroke.width||1)/2)),y1:y-open,y2:y-open},cl={x1:((_131/2)-((_137.series.stroke.width||1)/2)),x2:_131,y1:y-_138,y2:y-_138};var _139=s.createGroup();_139.setTransform({dx:x,dy:0});var _13a=_139.createGroup();_13a.createLine(hl).setStroke(_137.series.stroke);_13a.createLine(op).setStroke(_137.series.stroke);_13a.createLine(cl).setStroke(_137.series.stroke);run.dyn.stroke=_137.series.stroke;if(_134){var o={element:"candlestick",index:j,run:run,shape:_13a,x:x,y:y-Math.max(open,_138),cx:_131/2,cy:(y-Math.max(open,_138))+(Math.max(open>_138?open-_138:_138-open,1)/2),width:_131,height:Math.max(open>_138?open-_138:_138-open,1),data:v};this._connectEvents(o);_136[j]=o;}}if(this.animate){this._animateOHLC(_139,y-low,high-low);}}}this._eventSeries[run.name]=_136;run.dirty=false;}this.dirty=false;return this;},_animateOHLC:function(_13b,_13c,_13d){fx.animateTransform(lang.delegate({shape:_13b,duration:1200,transform:[{name:"translate",start:[0,_13c-(_13c/_13d)],end:[0,0]},{name:"scale",start:[1,1/_13d],end:[1,1]},{name:"original"}]},this.animate)).play();}});});},"dojox/charting/plot2d/ClusteredColumns":function(){define("dojox/charting/plot2d/ClusteredColumns",["dojo/_base/array","dojo/_base/declare","./Columns","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils"],function(arr,_13e,_13f,dc,df,dfr,du){var _140=dfr.lambda("item.purgeGroup()");return _13e("dojox.charting.plot2d.ClusteredColumns",_13f,{render:function(dim,_141){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_141);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_140);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,f,gap,_142,_143,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_144=Math.max(0,this._vScaler.bounds.lower),_145=vt(_144),_146=this.events();f=dc.calculateBarSize(this._hScaler.bounds.scale,this.opt,this.series.length);gap=f.gap;_142=_143=f.size;for(var i=0;i<this.series.length;++i){var run=this.series[i],_147=_143*i;if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();var _148=t.next("column",[this.opt,run]),s=run.group,_149=new Array(run.data.length);for(var j=0;j<run.data.length;++j){var _14a=run.data[j];if(_14a!==null){var v=typeof _14a=="number"?_14a:_14a.y,vv=vt(v),_14b=vv-_145,h=Math.abs(_14b),_14c=typeof _14a!="number"?t.addMixin(_148,"column",_14a,true):t.post(_148,"column");if(_142>=1&&h>=0){var rect={x:_141.l+ht(j+0.5)+gap+_147,y:dim.height-_141.b-(v>_144?vv:_145),width:_142,height:h};var _14d=this._plotFill(_14c.series.fill,dim,_141);_14d=this._shapeFill(_14d,rect);var _14e=s.createRect(rect).setFill(_14d).setStroke(_14c.series.stroke);run.dyn.fill=_14e.getFill();run.dyn.stroke=_14e.getStroke();if(_146){var o={element:"column",index:j,run:run,shape:_14e,x:j+0.5,y:v};this._connectEvents(o);_149[j]=o;}if(this.animate){this._animateColumn(_14e,dim.height-_141.b-_145,h);}}}}this._eventSeries[run.name]=_149;run.dirty=false;}this.dirty=false;return this;}});});},"dojox/charting/Chart":function(){define("dojox/charting/Chart",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","dojo/_base/html","dojo/dom","dojo/dom-geometry","dojo/dom-construct","dojo/_base/Color","dojo/_base/sniff","./Element","./Theme","./Series","./axis2d/common","dojox/gfx","dojox/lang/functional","dojox/lang/functional/fold","dojox/lang/functional/reversed"],function(lang,arr,_14f,html,dom,_150,_151,_152,has,_153,_154,_155,_156,g,func,_157,_158){var dc=dojox.charting,_159=func.lambda("item.clear()"),_15a=func.lambda("item.purgeGroup()"),_15b=func.lambda("item.destroy()"),_15c=func.lambda("item.dirty = false"),_15d=func.lambda("item.dirty = true"),_15e=func.lambda("item.name");_14f("dojox.charting.Chart",null,{constructor:function(node,_15f){if(!_15f){_15f={};}this.margins=_15f.margins?_15f.margins:{l:10,t:10,r:10,b:10};this.stroke=_15f.stroke;this.fill=_15f.fill;this.delayInMs=_15f.delayInMs||200;this.title=_15f.title;this.titleGap=_15f.titleGap;this.titlePos=_15f.titlePos;this.titleFont=_15f.titleFont;this.titleFontColor=_15f.titleFontColor;this.chartTitle=null;this.theme=null;this.axes={};this.stack=[];this.plots={};this.series=[];this.runs={};this.dirty=true;this.coords=null;this.node=dom.byId(node);var box=_150.getMarginBox(node);this.surface=g.createSurface(this.node,box.w||400,box.h||300);},destroy:function(){arr.forEach(this.series,_15b);arr.forEach(this.stack,_15b);func.forIn(this.axes,_15b);if(this.chartTitle&&this.chartTitle.tagName){_151.destroy(this.chartTitle);}this.surface.destroy();},getCoords:function(){return html.coords(this.node,true);},setTheme:function(_160){this.theme=_160.clone();this.dirty=true;return this;},addAxis:function(name,_161){var axis,_162=_161&&_161.type||"Default";if(typeof _162=="string"){if(!dc.axis2d||!dc.axis2d[_162]){throw Error("Can't find axis: "+_162+" - Check "+"require() dependencies.");}axis=new dc.axis2d[_162](this,_161);}else{axis=new _162(this,_161);}axis.name=name;axis.dirty=true;if(name in this.axes){this.axes[name].destroy();}this.axes[name]=axis;this.dirty=true;return this;},getAxis:function(name){return this.axes[name];},removeAxis:function(name){if(name in this.axes){this.axes[name].destroy();delete this.axes[name];this.dirty=true;}return this;},addPlot:function(name,_163){var plot,_164=_163&&_163.type||"Default";if(typeof _164=="string"){if(!dc.plot2d||!dc.plot2d[_164]){throw Error("Can't find plot: "+_164+" - didn't you forget to dojo"+".require() it?");}plot=new dc.plot2d[_164](this,_163);}else{plot=new _164(this,_163);}plot.name=name;plot.dirty=true;if(name in this.plots){this.stack[this.plots[name]].destroy();this.stack[this.plots[name]]=plot;}else{this.plots[name]=this.stack.length;this.stack.push(plot);}this.dirty=true;return this;},getPlot:function(name){return this.stack[this.plots[name]];},removePlot:function(name){if(name in this.plots){var _165=this.plots[name];delete this.plots[name];this.stack[_165].destroy();this.stack.splice(_165,1);func.forIn(this.plots,function(idx,name,_166){if(idx>_165){_166[name]=idx-1;}});var ns=arr.filter(this.series,function(run){return run.plot!=name;});if(ns.length<this.series.length){arr.forEach(this.series,function(run){if(run.plot==name){run.destroy();}});this.runs={};arr.forEach(ns,function(run,_167){this.runs[run.plot]=_167;},this);this.series=ns;}this.dirty=true;}return this;},getPlotOrder:function(){return func.map(this.stack,_15e);},setPlotOrder:function(_168){var _169={},_16a=func.filter(_168,function(name){if(!(name in this.plots)||(name in _169)){return false;}_169[name]=1;return true;},this);if(_16a.length<this.stack.length){func.forEach(this.stack,function(plot){var name=plot.name;if(!(name in _169)){_16a.push(name);}});}var _16b=func.map(_16a,function(name){return this.stack[this.plots[name]];},this);func.forEach(_16b,function(plot,i){this.plots[plot.name]=i;},this);this.stack=_16b;this.dirty=true;return this;},movePlotToFront:function(name){if(name in this.plots){var _16c=this.plots[name];if(_16c){var _16d=this.getPlotOrder();_16d.splice(_16c,1);_16d.unshift(name);return this.setPlotOrder(_16d);}}return this;},movePlotToBack:function(name){if(name in this.plots){var _16e=this.plots[name];if(_16e<this.stack.length-1){var _16f=this.getPlotOrder();_16f.splice(_16e,1);_16f.push(name);return this.setPlotOrder(_16f);}}return this;},addSeries:function(name,data,_170){var run=new _155(this,data,_170);run.name=name;if(name in this.runs){this.series[this.runs[name]].destroy();this.series[this.runs[name]]=run;}else{this.runs[name]=this.series.length;this.series.push(run);}this.dirty=true;if(!("ymin" in run)&&"min" in run){run.ymin=run.min;}if(!("ymax" in run)&&"max" in run){run.ymax=run.max;}return this;},getSeries:function(name){return this.series[this.runs[name]];},removeSeries:function(name){if(name in this.runs){var _171=this.runs[name];delete this.runs[name];this.series[_171].destroy();this.series.splice(_171,1);func.forIn(this.runs,function(idx,name,runs){if(idx>_171){runs[name]=idx-1;}});this.dirty=true;}return this;},updateSeries:function(name,data){if(name in this.runs){var run=this.series[this.runs[name]];run.update(data);this._invalidateDependentPlots(run.plot,false);this._invalidateDependentPlots(run.plot,true);}return this;},getSeriesOrder:function(_172){return func.map(func.filter(this.series,function(run){return run.plot==_172;}),_15e);},setSeriesOrder:function(_173){var _174,_175={},_176=func.filter(_173,function(name){if(!(name in this.runs)||(name in _175)){return false;}var run=this.series[this.runs[name]];if(_174){if(run.plot!=_174){return false;}}else{_174=run.plot;}_175[name]=1;return true;},this);func.forEach(this.series,function(run){var name=run.name;if(!(name in _175)&&run.plot==_174){_176.push(name);}});var _177=func.map(_176,function(name){return this.series[this.runs[name]];},this);this.series=_177.concat(func.filter(this.series,function(run){return run.plot!=_174;}));func.forEach(this.series,function(run,i){this.runs[run.name]=i;},this);this.dirty=true;return this;},moveSeriesToFront:function(name){if(name in this.runs){var _178=this.runs[name],_179=this.getSeriesOrder(this.series[_178].plot);if(name!=_179[0]){_179.splice(_178,1);_179.unshift(name);return this.setSeriesOrder(_179);}}return this;},moveSeriesToBack:function(name){if(name in this.runs){var _17a=this.runs[name],_17b=this.getSeriesOrder(this.series[_17a].plot);if(name!=_17b[_17b.length-1]){_17b.splice(_17a,1);_17b.push(name);return this.setSeriesOrder(_17b);}}return this;},resize:function(_17c,_17d){var box;switch(arguments.length){case 1:box=lang.mixin({},_17c);_150.setMarginBox(this.node,box);break;case 2:box={w:_17c,h:_17d};_150.setMarginBox(this.node,box);break;}box=_150.getMarginBox(this.node);var d=this.surface.getDimensions();if(d.width!=box.w||d.height!=box.h){this.surface.setDimensions(box.w,box.h);this.dirty=true;return this.render();}else{return this;}},getGeometry:function(){var ret={};func.forIn(this.axes,function(axis){if(axis.initialized()){ret[axis.name]={name:axis.name,vertical:axis.vertical,scaler:axis.scaler,ticks:axis.ticks};}});return ret;},setAxisWindow:function(name,_17e,_17f,zoom){var axis=this.axes[name];if(axis){axis.setWindow(_17e,_17f);arr.forEach(this.stack,function(plot){if(plot.hAxis==name||plot.vAxis==name){plot.zoom=zoom;}});}return this;},setWindow:function(sx,sy,dx,dy,zoom){if(!("plotArea" in this)){this.calculateGeometry();}func.forIn(this.axes,function(axis){var _180,_181,_182=axis.getScaler().bounds,s=_182.span/(_182.upper-_182.lower);if(axis.vertical){_180=sy;_181=dy/s/_180;}else{_180=sx;_181=dx/s/_180;}axis.setWindow(_180,_181);});arr.forEach(this.stack,function(plot){plot.zoom=zoom;});return this;},zoomIn:function(name,_183){var axis=this.axes[name];if(axis){var _184,_185,_186=axis.getScaler().bounds;var _187=Math.min(_183[0],_183[1]);var _188=Math.max(_183[0],_183[1]);_187=_183[0]<_186.lower?_186.lower:_187;_188=_183[1]>_186.upper?_186.upper:_188;_184=(_186.upper-_186.lower)/(_188-_187);_185=_187-_186.lower;this.setAxisWindow(name,_184,_185);this.render();}},calculateGeometry:function(){if(this.dirty){return this.fullGeometry();}var _189=arr.filter(this.stack,function(plot){return plot.dirty||(plot.hAxis&&this.axes[plot.hAxis].dirty)||(plot.vAxis&&this.axes[plot.vAxis].dirty);},this);_18a(_189,this.plotArea);return this;},fullGeometry:function(){this._makeDirty();arr.forEach(this.stack,_159);if(!this.theme){this.setTheme(new _154(dojox.charting._def));}arr.forEach(this.series,function(run){if(!(run.plot in this.plots)){if(!dc.plot2d||!dc.plot2d.Default){throw Error("Can't find plot: Default - didn't you forget to dojo"+".require() it?");}var plot=new dc.plot2d.Default(this,{});plot.name=run.plot;this.plots[run.plot]=this.stack.length;this.stack.push(plot);}this.stack[this.plots[run.plot]].addSeries(run);},this);arr.forEach(this.stack,function(plot){if(plot.hAxis){plot.setAxis(this.axes[plot.hAxis]);}if(plot.vAxis){plot.setAxis(this.axes[plot.vAxis]);}},this);var dim=this.dim=this.surface.getDimensions();dim.width=g.normalizedLength(dim.width);dim.height=g.normalizedLength(dim.height);func.forIn(this.axes,_159);_18a(this.stack,dim);var _18b=this.offsets={l:0,r:0,t:0,b:0};func.forIn(this.axes,function(axis){func.forIn(axis.getOffsets(),function(o,i){_18b[i]+=o;});});if(this.title){this.titleGap=(this.titleGap==0)?0:this.titleGap||this.theme.chart.titleGap||20;this.titlePos=this.titlePos||this.theme.chart.titlePos||"top";this.titleFont=this.titleFont||this.theme.chart.titleFont;this.titleFontColor=this.titleFontColor||this.theme.chart.titleFontColor||"black";var _18c=g.normalizedLength(g.splitFontString(this.titleFont).size);_18b[this.titlePos=="top"?"t":"b"]+=(_18c+this.titleGap);}func.forIn(this.margins,function(o,i){_18b[i]+=o;});this.plotArea={width:dim.width-_18b.l-_18b.r,height:dim.height-_18b.t-_18b.b};func.forIn(this.axes,_159);_18a(this.stack,this.plotArea);return this;},render:function(){if(this.theme){this.theme.clear();}if(this.dirty){return this.fullRender();}this.calculateGeometry();func.forEachRev(this.stack,function(plot){plot.render(this.dim,this.offsets);},this);func.forIn(this.axes,function(axis){axis.render(this.dim,this.offsets);},this);this._makeClean();if(this.surface.render){this.surface.render();}return this;},fullRender:function(){this.fullGeometry();var _18d=this.offsets,dim=this.dim,rect;arr.forEach(this.series,_15a);func.forIn(this.axes,_15a);arr.forEach(this.stack,_15a);if(this.chartTitle&&this.chartTitle.tagName){_151.destroy(this.chartTitle);}this.surface.clear();this.chartTitle=null;var t=this.theme,fill=t.plotarea&&t.plotarea.fill,_18e=t.plotarea&&t.plotarea.stroke,w=Math.max(0,dim.width-_18d.l-_18d.r),h=Math.max(0,dim.height-_18d.t-_18d.b),rect={x:_18d.l-1,y:_18d.t-1,width:w+2,height:h+2};if(fill){fill=_153.prototype._shapeFill(_153.prototype._plotFill(fill,dim,_18d),rect);this.surface.createRect(rect).setFill(fill);}if(_18e){this.surface.createRect({x:_18d.l,y:_18d.t,width:w+1,height:h+1}).setStroke(_18e);}func.foldr(this.stack,function(z,plot){return plot.render(dim,_18d),0;},0);fill=this.fill!==undefined?this.fill:(t.chart&&t.chart.fill);_18e=this.stroke!==undefined?this.stroke:(t.chart&&t.chart.stroke);if(fill=="inherit"){var node=this.node,fill=new _152(html.style(node,"backgroundColor"));while(fill.a==0&&node!=document.documentElement){fill=new _152(html.style(node,"backgroundColor"));node=node.parentNode;}}if(fill){fill=_153.prototype._plotFill(fill,dim,_18d);if(_18d.l){rect={width:_18d.l,height:dim.height+1};this.surface.createRect(rect).setFill(_153.prototype._shapeFill(fill,rect));}if(_18d.r){rect={x:dim.width-_18d.r,width:_18d.r+1,height:dim.height+2};this.surface.createRect(rect).setFill(_153.prototype._shapeFill(fill,rect));}if(_18d.t){rect={width:dim.width+1,height:_18d.t};this.surface.createRect(rect).setFill(_153.prototype._shapeFill(fill,rect));}if(_18d.b){rect={y:dim.height-_18d.b,width:dim.width+1,height:_18d.b+2};this.surface.createRect(rect).setFill(_153.prototype._shapeFill(fill,rect));}}if(_18e){this.surface.createRect({width:dim.width-1,height:dim.height-1}).setStroke(_18e);}if(this.title){var _18f=(g.renderer=="canvas"),_190=_18f||!has("ie")&&!has("opera")?"html":"gfx",_191=g.normalizedLength(g.splitFontString(this.titleFont).size);this.chartTitle=_156.createText[_190](this,this.surface,dim.width/2,this.titlePos=="top"?_191+this.margins.t:dim.height-this.margins.b,"middle",this.title,this.titleFont,this.titleFontColor);}func.forIn(this.axes,function(axis){axis.render(dim,_18d);});this._makeClean();if(this.surface.render){this.surface.render();}return this;},delayedRender:function(){if(!this._delayedRenderHandle){this._delayedRenderHandle=setTimeout(lang.hitch(this,function(){clearTimeout(this._delayedRenderHandle);this._delayedRenderHandle=null;this.render();}),this.delayInMs);}return this;},connectToPlot:function(name,_192,_193){return name in this.plots?this.stack[this.plots[name]].connect(_192,_193):null;},fireEvent:function(_194,_195,_196){if(_194 in this.runs){var _197=this.series[this.runs[_194]].plot;if(_197 in this.plots){var plot=this.stack[this.plots[_197]];if(plot){plot.fireEvent(_194,_195,_196);}}}return this;},_makeClean:function(){arr.forEach(this.axes,_15c);arr.forEach(this.stack,_15c);arr.forEach(this.series,_15c);this.dirty=false;},_makeDirty:function(){arr.forEach(this.axes,_15d);arr.forEach(this.stack,_15d);arr.forEach(this.series,_15d);this.dirty=true;},_invalidateDependentPlots:function(_198,_199){if(_198 in this.plots){var plot=this.stack[this.plots[_198]],axis,_19a=_199?"vAxis":"hAxis";if(plot[_19a]){axis=this.axes[plot[_19a]];if(axis&&axis.dependOnData()){axis.dirty=true;arr.forEach(this.stack,function(p){if(p[_19a]&&p[_19a]==plot[_19a]){p.dirty=true;}});}}else{plot.dirty=true;}}}});function _19b(_19c){return {min:_19c.hmin,max:_19c.hmax};};function _19d(_19e){return {min:_19e.vmin,max:_19e.vmax};};function _19f(_1a0,h){_1a0.hmin=h.min;_1a0.hmax=h.max;};function _1a1(_1a2,v){_1a2.vmin=v.min;_1a2.vmax=v.max;};function _1a3(_1a4,_1a5){if(_1a4&&_1a5){_1a4.min=Math.min(_1a4.min,_1a5.min);_1a4.max=Math.max(_1a4.max,_1a5.max);}return _1a4||_1a5;};function _18a(_1a6,_1a7){var _1a8={},axes={};arr.forEach(_1a6,function(plot){var _1a9=_1a8[plot.name]=plot.getSeriesStats();if(plot.hAxis){axes[plot.hAxis]=_1a3(axes[plot.hAxis],_19b(_1a9));}if(plot.vAxis){axes[plot.vAxis]=_1a3(axes[plot.vAxis],_19d(_1a9));}});arr.forEach(_1a6,function(plot){var _1aa=_1a8[plot.name];if(plot.hAxis){_19f(_1aa,axes[plot.hAxis]);}if(plot.vAxis){_1a1(_1aa,axes[plot.vAxis]);}plot.initializeScalers(_1a7,_1aa);});};return dojox.charting.Chart;});},"dojox/lang/functional/sequence":function(){define("dojox/lang/functional/sequence",["dojo/_base/lang","./lambda"],function(lang,df){lang.mixin(df,{repeat:function(n,f,z,o){o=o||dojo.global;f=df.lambda(f);var t=new Array(n),i=1;t[0]=z;for(;i<n;t[i]=z=f.call(o,z),++i){}return t;},until:function(pr,f,z,o){o=o||dojo.global;f=df.lambda(f);pr=df.lambda(pr);var t=[];for(;!pr.call(o,z);t.push(z),z=f.call(o,z)){}return t;}});return df;});},"dojox/charting/plot2d/MarkersOnly":function(){define("dojox/charting/plot2d/MarkersOnly",["dojo/_base/declare","./Default"],function(_1ab,_1ac){return _1ab("dojox.charting.plot2d.MarkersOnly",_1ac,{constructor:function(){this.opt.lines=false;this.opt.markers=true;}});});},"dojox/charting/plot2d/Areas":function(){define("dojox/charting/plot2d/Areas",["dojo/_base/declare","./Default"],function(_1ad,_1ae){return _1ad("dojox.charting.plot2d.Areas",_1ae,{constructor:function(){this.opt.lines=true;this.opt.areas=true;}});});},"dojox/charting/action2d/Base":function(){define("dojox/charting/action2d/Base",["dojo/_base/lang","dojo/_base/declare"],function(lang,_1af){return _1af("dojox.charting.action2d.Base",null,{constructor:function(_1b0,plot){this.chart=_1b0;this.plot=plot?(lang.isString(plot)?this.chart.getPlot(plot):plot):this.chart.getPlot("default");},connect:function(){},disconnect:function(){},destroy:function(){this.disconnect();}});});},"dojo/fx":function(){define(["./_base/lang","./Evented","./_base/kernel","./_base/array","./_base/connect","./_base/fx","./dom","./dom-style","./dom-geometry","./ready","require"],function(lang,_1b1,dojo,_1b2,_1b3,_1b4,dom,_1b5,geom,_1b6,_1b7){if(!dojo.isAsync){_1b6(0,function(){var _1b8=["./fx/Toggler"];_1b7(_1b8);});}var _1b9=dojo.fx={};var _1ba={_fire:function(evt,args){if(this[evt]){this[evt].apply(this,args||[]);}return this;}};var _1bb=function(_1bc){this._index=-1;this._animations=_1bc||[];this._current=this._onAnimateCtx=this._onEndCtx=null;this.duration=0;_1b2.forEach(this._animations,function(a){this.duration+=a.duration;if(a.delay){this.duration+=a.delay;}},this);};_1bb.prototype=new _1b1();lang.extend(_1bb,{_onAnimate:function(){this._fire("onAnimate",arguments);},_onEnd:function(){_1b3.disconnect(this._onAnimateCtx);_1b3.disconnect(this._onEndCtx);this._onAnimateCtx=this._onEndCtx=null;if(this._index+1==this._animations.length){this._fire("onEnd");}else{this._current=this._animations[++this._index];this._onAnimateCtx=_1b3.connect(this._current,"onAnimate",this,"_onAnimate");this._onEndCtx=_1b3.connect(this._current,"onEnd",this,"_onEnd");this._current.play(0,true);}},play:function(_1bd,_1be){if(!this._current){this._current=this._animations[this._index=0];}if(!_1be&&this._current.status()=="playing"){return this;}var _1bf=_1b3.connect(this._current,"beforeBegin",this,function(){this._fire("beforeBegin");}),_1c0=_1b3.connect(this._current,"onBegin",this,function(arg){this._fire("onBegin",arguments);}),_1c1=_1b3.connect(this._current,"onPlay",this,function(arg){this._fire("onPlay",arguments);_1b3.disconnect(_1bf);_1b3.disconnect(_1c0);_1b3.disconnect(_1c1);});if(this._onAnimateCtx){_1b3.disconnect(this._onAnimateCtx);}this._onAnimateCtx=_1b3.connect(this._current,"onAnimate",this,"_onAnimate");if(this._onEndCtx){_1b3.disconnect(this._onEndCtx);}this._onEndCtx=_1b3.connect(this._current,"onEnd",this,"_onEnd");this._current.play.apply(this._current,arguments);return this;},pause:function(){if(this._current){var e=_1b3.connect(this._current,"onPause",this,function(arg){this._fire("onPause",arguments);_1b3.disconnect(e);});this._current.pause();}return this;},gotoPercent:function(_1c2,_1c3){this.pause();var _1c4=this.duration*_1c2;this._current=null;_1b2.some(this._animations,function(a){if(a.duration<=_1c4){this._current=a;return true;}_1c4-=a.duration;return false;});if(this._current){this._current.gotoPercent(_1c4/this._current.duration,_1c3);}return this;},stop:function(_1c5){if(this._current){if(_1c5){for(;this._index+1<this._animations.length;++this._index){this._animations[this._index].stop(true);}this._current=this._animations[this._index];}var e=_1b3.connect(this._current,"onStop",this,function(arg){this._fire("onStop",arguments);_1b3.disconnect(e);});this._current.stop();}return this;},status:function(){return this._current?this._current.status():"stopped";},destroy:function(){if(this._onAnimateCtx){_1b3.disconnect(this._onAnimateCtx);}if(this._onEndCtx){_1b3.disconnect(this._onEndCtx);}}});lang.extend(_1bb,_1ba);_1b9.chain=function(_1c6){return new _1bb(_1c6);};var _1c7=function(_1c8){this._animations=_1c8||[];this._connects=[];this._finished=0;this.duration=0;_1b2.forEach(_1c8,function(a){var _1c9=a.duration;if(a.delay){_1c9+=a.delay;}if(this.duration<_1c9){this.duration=_1c9;}this._connects.push(_1b3.connect(a,"onEnd",this,"_onEnd"));},this);this._pseudoAnimation=new _1b4.Animation({curve:[0,1],duration:this.duration});var self=this;_1b2.forEach(["beforeBegin","onBegin","onPlay","onAnimate","onPause","onStop","onEnd"],function(evt){self._connects.push(_1b3.connect(self._pseudoAnimation,evt,function(){self._fire(evt,arguments);}));});};lang.extend(_1c7,{_doAction:function(_1ca,args){_1b2.forEach(this._animations,function(a){a[_1ca].apply(a,args);});return this;},_onEnd:function(){if(++this._finished>this._animations.length){this._fire("onEnd");}},_call:function(_1cb,args){var t=this._pseudoAnimation;t[_1cb].apply(t,args);},play:function(_1cc,_1cd){this._finished=0;this._doAction("play",arguments);this._call("play",arguments);return this;},pause:function(){this._doAction("pause",arguments);this._call("pause",arguments);return this;},gotoPercent:function(_1ce,_1cf){var ms=this.duration*_1ce;_1b2.forEach(this._animations,function(a){a.gotoPercent(a.duration<ms?1:(ms/a.duration),_1cf);});this._call("gotoPercent",arguments);return this;},stop:function(_1d0){this._doAction("stop",arguments);this._call("stop",arguments);return this;},status:function(){return this._pseudoAnimation.status();},destroy:function(){_1b2.forEach(this._connects,_1b3.disconnect);}});lang.extend(_1c7,_1ba);_1b9.combine=function(_1d1){return new _1c7(_1d1);};_1b9.wipeIn=function(args){var node=args.node=dom.byId(args.node),s=node.style,o;var anim=_1b4.animateProperty(lang.mixin({properties:{height:{start:function(){o=s.overflow;s.overflow="hidden";if(s.visibility=="hidden"||s.display=="none"){s.height="1px";s.display="";s.visibility="";return 1;}else{var _1d2=_1b5.get(node,"height");return Math.max(_1d2,1);}},end:function(){return node.scrollHeight;}}}},args));var fini=function(){s.height="auto";s.overflow=o;};_1b3.connect(anim,"onStop",fini);_1b3.connect(anim,"onEnd",fini);return anim;};_1b9.wipeOut=function(args){var node=args.node=dom.byId(args.node),s=node.style,o;var anim=_1b4.animateProperty(lang.mixin({properties:{height:{end:1}}},args));_1b3.connect(anim,"beforeBegin",function(){o=s.overflow;s.overflow="hidden";s.display="";});var fini=function(){s.overflow=o;s.height="auto";s.display="none";};_1b3.connect(anim,"onStop",fini);_1b3.connect(anim,"onEnd",fini);return anim;};_1b9.slideTo=function(args){var node=args.node=dom.byId(args.node),top=null,left=null;var init=(function(n){return function(){var cs=_1b5.getComputedStyle(n);var pos=cs.position;top=(pos=="absolute"?n.offsetTop:parseInt(cs.top)||0);left=(pos=="absolute"?n.offsetLeft:parseInt(cs.left)||0);if(pos!="absolute"&&pos!="relative"){var ret=geom.position(n,true);top=ret.y;left=ret.x;n.style.position="absolute";n.style.top=top+"px";n.style.left=left+"px";}};})(node);init();var anim=_1b4.animateProperty(lang.mixin({properties:{top:args.top||0,left:args.left||0}},args));_1b3.connect(anim,"beforeBegin",anim,init);return anim;};return _1b9;});},"dojox/gfx/fx":function(){define("dojox/gfx/fx",["dojo/_base/lang","./_base","./matrix","dojo/_base/Color","dojo/_base/array","dojo/_base/fx","dojo/_base/connect"],function(lang,g,m,_1d3,arr,fx,Hub){var fxg=g.fx={};function _1d4(_1d5,end){this.start=_1d5,this.end=end;};_1d4.prototype.getValue=function(r){return (this.end-this.start)*r+this.start;};function _1d6(_1d7,end,_1d8){this.start=_1d7,this.end=end;this.units=_1d8;};_1d6.prototype.getValue=function(r){return (this.end-this.start)*r+this.start+this.units;};function _1d9(_1da,end){this.start=_1da,this.end=end;this.temp=new _1d3();};_1d9.prototype.getValue=function(r){return _1d3.blendColors(this.start,this.end,r,this.temp);};function _1db(_1dc){this.values=_1dc;this.length=_1dc.length;};_1db.prototype.getValue=function(r){return this.values[Math.min(Math.floor(r*this.length),this.length-1)];};function _1dd(_1de,def){this.values=_1de;this.def=def?def:{};};_1dd.prototype.getValue=function(r){var ret=lang.clone(this.def);for(var i in this.values){ret[i]=this.values[i].getValue(r);}return ret;};function _1df(_1e0,_1e1){this.stack=_1e0;this.original=_1e1;};_1df.prototype.getValue=function(r){var ret=[];arr.forEach(this.stack,function(t){if(t instanceof m.Matrix2D){ret.push(t);return;}if(t.name=="original"&&this.original){ret.push(this.original);return;}if(!(t.name in m)){return;}var f=m[t.name];if(typeof f!="function"){ret.push(f);return;}var val=arr.map(t.start,function(v,i){return (t.end[i]-v)*r+v;}),_1e2=f.apply(m,val);if(_1e2 instanceof m.Matrix2D){ret.push(_1e2);}},this);return ret;};var _1e3=new _1d3(0,0,0,0);function _1e4(prop,obj,name,def){if(prop.values){return new _1db(prop.values);}var _1e5,_1e6,end;if(prop.start){_1e6=g.normalizeColor(prop.start);}else{_1e6=_1e5=obj?(name?obj[name]:obj):def;}if(prop.end){end=g.normalizeColor(prop.end);}else{if(!_1e5){_1e5=obj?(name?obj[name]:obj):def;}end=_1e5;}return new _1d9(_1e6,end);};function _1e7(prop,obj,name,def){if(prop.values){return new _1db(prop.values);}var _1e8,_1e9,end;if(prop.start){_1e9=prop.start;}else{_1e9=_1e8=obj?obj[name]:def;}if(prop.end){end=prop.end;}else{if(typeof _1e8!="number"){_1e8=obj?obj[name]:def;}end=_1e8;}return new _1d4(_1e9,end);};fxg.animateStroke=function(args){if(!args.easing){args.easing=fx._defaultEasing;}var anim=new fx.Animation(args),_1ea=args.shape,_1eb;Hub.connect(anim,"beforeBegin",anim,function(){_1eb=_1ea.getStroke();var prop=args.color,_1ec={},_1ed,_1ee,end;if(prop){_1ec.color=_1e4(prop,_1eb,"color",_1e3);}prop=args.style;if(prop&&prop.values){_1ec.style=new _1db(prop.values);}prop=args.width;if(prop){_1ec.width=_1e7(prop,_1eb,"width",1);}prop=args.cap;if(prop&&prop.values){_1ec.cap=new _1db(prop.values);}prop=args.join;if(prop){if(prop.values){_1ec.join=new _1db(prop.values);}else{_1ee=prop.start?prop.start:(_1eb&&_1eb.join||0);end=prop.end?prop.end:(_1eb&&_1eb.join||0);if(typeof _1ee=="number"&&typeof end=="number"){_1ec.join=new _1d4(_1ee,end);}}}this.curve=new _1dd(_1ec,_1eb);});Hub.connect(anim,"onAnimate",_1ea,"setStroke");return anim;};fxg.animateFill=function(args){if(!args.easing){args.easing=fx._defaultEasing;}var anim=new fx.Animation(args),_1ef=args.shape,fill;Hub.connect(anim,"beforeBegin",anim,function(){fill=_1ef.getFill();var prop=args.color,_1f0={};if(prop){this.curve=_1e4(prop,fill,"",_1e3);}});Hub.connect(anim,"onAnimate",_1ef,"setFill");return anim;};fxg.animateFont=function(args){if(!args.easing){args.easing=fx._defaultEasing;}var anim=new fx.Animation(args),_1f1=args.shape,font;Hub.connect(anim,"beforeBegin",anim,function(){font=_1f1.getFont();var prop=args.style,_1f2={},_1f3,_1f4,end;if(prop&&prop.values){_1f2.style=new _1db(prop.values);}prop=args.variant;if(prop&&prop.values){_1f2.variant=new _1db(prop.values);}prop=args.weight;if(prop&&prop.values){_1f2.weight=new _1db(prop.values);}prop=args.family;if(prop&&prop.values){_1f2.family=new _1db(prop.values);}prop=args.size;if(prop&&prop.units){_1f4=parseFloat(prop.start?prop.start:(_1f1.font&&_1f1.font.size||"0"));end=parseFloat(prop.end?prop.end:(_1f1.font&&_1f1.font.size||"0"));_1f2.size=new _1d6(_1f4,end,prop.units);}this.curve=new _1dd(_1f2,font);});Hub.connect(anim,"onAnimate",_1f1,"setFont");return anim;};fxg.animateTransform=function(args){if(!args.easing){args.easing=fx._defaultEasing;}var anim=new fx.Animation(args),_1f5=args.shape,_1f6;Hub.connect(anim,"beforeBegin",anim,function(){_1f6=_1f5.getTransform();this.curve=new _1df(args.transform,_1f6);});Hub.connect(anim,"onAnimate",_1f5,"setTransform");return anim;};return fxg;});},"dojox/charting/action2d/PlotAction":function(){define("dojox/charting/action2d/PlotAction",["dojo/_base/connect","dojo/_base/declare","./Base","dojo/fx/easing","dojox/lang/functional","dojox/lang/functional/object"],function(hub,_1f7,Base,dfe,df,dlfo){var _1f8=400,_1f9=dfe.backOut;return _1f7("dojox.charting.action2d.PlotAction",Base,{overOutEvents:{onmouseover:1,onmouseout:1},constructor:function(_1fa,plot,_1fb){this.anim={};if(!_1fb){_1fb={};}this.duration=_1fb.duration?_1fb.duration:_1f8;this.easing=_1fb.easing?_1fb.easing:_1f9;},connect:function(){this.handle=this.chart.connectToPlot(this.plot.name,this,"process");},disconnect:function(){if(this.handle){hub.disconnect(this.handle);this.handle=null;}},reset:function(){},destroy:function(){this.inherited(arguments);df.forIn(this.anim,function(o){df.forIn(o,function(anim){anim.action.stop(true);});});this.anim={};}});});},"dijit/BackgroundIframe":function(){define("dijit/BackgroundIframe",["require",".","dojo/_base/config","dojo/dom-construct","dojo/dom-style","dojo/_base/lang","dojo/on","dojo/_base/sniff","dojo/_base/window"],function(_1fc,_1fd,_1fe,_1ff,_200,lang,on,has,win){var _201=new function(){var _202=[];this.pop=function(){var _203;if(_202.length){_203=_202.pop();_203.style.display="";}else{if(has("ie")<9){var burl=_1fe["dojoBlankHtmlUrl"]||_1fc.toUrl("dojo/resources/blank.html")||"javascript:\"\"";var html="<iframe src='"+burl+"' role='presentation'"+" style='position: absolute; left: 0px; top: 0px;"+"z-index: -1; filter:Alpha(Opacity=\"0\");'>";_203=win.doc.createElement(html);}else{_203=_1ff.create("iframe");_203.src="javascript:\"\"";_203.className="dijitBackgroundIframe";_203.setAttribute("role","presentation");_200.set(_203,"opacity",0.1);}_203.tabIndex=-1;}return _203;};this.push=function(_204){_204.style.display="none";_202.push(_204);};}();_1fd.BackgroundIframe=function(node){if(!node.id){throw new Error("no id");}if(has("ie")||has("mozilla")){var _205=(this.iframe=_201.pop());node.appendChild(_205);if(has("ie")<7||has("quirks")){this.resize(node);this._conn=on(node,"resize",lang.hitch(this,function(){this.resize(node);}));}else{_200.set(_205,{width:"100%",height:"100%"});}}};lang.extend(_1fd.BackgroundIframe,{resize:function(node){if(this.iframe){_200.set(this.iframe,{width:node.offsetWidth+"px",height:node.offsetHeight+"px"});}},destroy:function(){if(this._conn){this._conn.remove();this._conn=null;}if(this.iframe){_201.push(this.iframe);delete this.iframe;}}});return _1fd.BackgroundIframe;});},"dojox/main":function(){define("dojox/main",["dojo/_base/kernel"],function(dojo){return dojo.dojox;});},"dojox/charting/action2d/Magnify":function(){define("dojox/charting/action2d/Magnify",["dojo/_base/connect","dojo/_base/declare","./PlotAction","dojox/gfx/matrix","dojox/gfx/fx","dojo/fx","dojo/fx/easing"],function(Hub,_206,_207,m,gf,df,dfe){var _208=2;return _206("dojox.charting.action2d.Magnify",_207,{defaultParams:{duration:400,easing:dfe.backOut,scale:_208},optionalParams:{},constructor:function(_209,plot,_20a){this.scale=_20a&&typeof _20a.scale=="number"?_20a.scale:_208;this.connect();},process:function(o){if(!o.shape||!(o.type in this.overOutEvents)||!("cx" in o)||!("cy" in o)){return;}var _20b=o.run.name,_20c=o.index,_20d=[],anim,init,_20e;if(_20b in this.anim){anim=this.anim[_20b][_20c];}else{this.anim[_20b]={};}if(anim){anim.action.stop(true);}else{this.anim[_20b][_20c]=anim={};}if(o.type=="onmouseover"){init=m.identity;_20e=this.scale;}else{init=m.scaleAt(this.scale,o.cx,o.cy);_20e=1/this.scale;}var _20f={shape:o.shape,duration:this.duration,easing:this.easing,transform:[{name:"scaleAt",start:[1,o.cx,o.cy],end:[_20e,o.cx,o.cy]},init]};if(o.shape){_20d.push(gf.animateTransform(_20f));}if(o.oultine){_20f.shape=o.outline;_20d.push(gf.animateTransform(_20f));}if(o.shadow){_20f.shape=o.shadow;_20d.push(gf.animateTransform(_20f));}if(!_20d.length){delete this.anim[_20b][_20c];return;}anim.action=df.combine(_20d);if(o.type=="onmouseout"){Hub.connect(anim.action,"onEnd",this,function(){if(this.anim[_20b]){delete this.anim[_20b][_20c];}});}anim.action.play();}});});},"dojo/Stateful":function(){define(["./_base/kernel","./_base/declare","./_base/lang","./_base/array"],function(dojo,_210,lang,_211){return dojo.declare("dojo.Stateful",null,{postscript:function(_212){if(_212){lang.mixin(this,_212);}},get:function(name){return this[name];},set:function(name,_213){if(typeof name==="object"){for(var x in name){this.set(x,name[x]);}return this;}var _214=this[name];this[name]=_213;if(this._watchCallbacks){this._watchCallbacks(name,_214,_213);}return this;},watch:function(name,_215){var _216=this._watchCallbacks;if(!_216){var self=this;_216=this._watchCallbacks=function(name,_217,_218,_219){var _21a=function(_21b){if(_21b){_21b=_21b.slice();for(var i=0,l=_21b.length;i<l;i++){try{_21b[i].call(self,name,_217,_218);}catch(e){console.error(e);}}}};_21a(_216["_"+name]);if(!_219){_21a(_216["*"]);}};}if(!_215&&typeof name==="function"){_215=name;name="*";}else{name="_"+name;}var _21c=_216[name];if(typeof _21c!=="object"){_21c=_216[name]=[];}_21c.push(_215);return {unwatch:function(){_21c.splice(_211.indexOf(_21c,_215),1);}};}});});},"dojox/charting/plot2d/Markers":function(){define("dojox/charting/plot2d/Markers",["dojo/_base/declare","./Default"],function(_21d,_21e){return _21d("dojox.charting.plot2d.Markers",_21e,{constructor:function(){this.opt.markers=true;}});});},"dojox/charting/plot2d/Bubble":function(){define("dojox/charting/plot2d/Bubble",["dojo/_base/lang","dojo/_base/declare","dojo/_base/array","./Base","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils","dojox/gfx/fx"],function(lang,_21f,arr,Base,dc,df,dfr,du,fx){var _220=dfr.lambda("item.purgeGroup()");return _21f("dojox.charting.plot2d.Bubble",Base,{defaultParams:{hAxis:"x",vAxis:"y",animate:null},optionalParams:{stroke:{},outline:{},shadow:{},fill:{},font:"",fontColor:""},constructor:function(_221,_222){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_222);du.updateWithPattern(this.opt,_222,this.optionalParams);this.series=[];this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.animate=this.opt.animate;},render:function(dim,_223){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_223);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_220);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_224=this.events();for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();if(!run.data.length){run.dirty=false;t.skip();continue;}if(typeof run.data[0]=="number"){console.warn("dojox.charting.plot2d.Bubble: the data in the following series cannot be rendered as a bubble chart; ",run);continue;}var _225=t.next("circle",[this.opt,run]),s=run.group,_226=arr.map(run.data,function(v,i){return v?{x:ht(v.x)+_223.l,y:dim.height-_223.b-vt(v.y),radius:this._vScaler.bounds.scale*(v.size/2)}:null;},this);var _227=null,_228=null,_229=null;if(_225.series.shadow){_229=arr.map(_226,function(item){if(item!==null){var _22a=t.addMixin(_225,"circle",item,true),_22b=_22a.series.shadow;var _22c=s.createCircle({cx:item.x+_22b.dx,cy:item.y+_22b.dy,r:item.radius}).setStroke(_22b).setFill(_22b.color);if(this.animate){this._animateBubble(_22c,dim.height-_223.b,item.radius);}return _22c;}return null;},this);if(_229.length){run.dyn.shadow=_229[_229.length-1].getStroke();}}if(_225.series.outline){_228=arr.map(_226,function(item){if(item!==null){var _22d=t.addMixin(_225,"circle",item,true),_22e=dc.makeStroke(_22d.series.outline);_22e.width=2*_22e.width+_225.series.stroke.width;var _22f=s.createCircle({cx:item.x,cy:item.y,r:item.radius}).setStroke(_22e);if(this.animate){this._animateBubble(_22f,dim.height-_223.b,item.radius);}return _22f;}return null;},this);if(_228.length){run.dyn.outline=_228[_228.length-1].getStroke();}}_227=arr.map(_226,function(item){if(item!==null){var _230=t.addMixin(_225,"circle",item,true),rect={x:item.x-item.radius,y:item.y-item.radius,width:2*item.radius,height:2*item.radius};var _231=this._plotFill(_230.series.fill,dim,_223);_231=this._shapeFill(_231,rect);var _232=s.createCircle({cx:item.x,cy:item.y,r:item.radius}).setFill(_231).setStroke(_230.series.stroke);if(this.animate){this._animateBubble(_232,dim.height-_223.b,item.radius);}return _232;}return null;},this);if(_227.length){run.dyn.fill=_227[_227.length-1].getFill();run.dyn.stroke=_227[_227.length-1].getStroke();}if(_224){var _233=new Array(_227.length);arr.forEach(_227,function(s,i){if(s!==null){var o={element:"circle",index:i,run:run,shape:s,outline:_228&&_228[i]||null,shadow:_229&&_229[i]||null,x:run.data[i].x,y:run.data[i].y,r:run.data[i].size/2,cx:_226[i].x,cy:_226[i].y,cr:_226[i].radius};this._connectEvents(o);_233[i]=o;}},this);this._eventSeries[run.name]=_233;}else{delete this._eventSeries[run.name];}run.dirty=false;}this.dirty=false;return this;},_animateBubble:function(_234,_235,size){fx.animateTransform(lang.delegate({shape:_234,duration:1200,transform:[{name:"translate",start:[0,_235],end:[0,0]},{name:"scale",start:[0,1/size],end:[1,1]},{name:"original"}]},this.animate)).play();}});});},"dojo/touch":function(){define(["./_base/kernel","./on","./has","./mouse"],function(dojo,on,has,_236){function _237(type){return function(node,_238){return on(node,type,_238);};};var _239=has("touch");dojo.touch={press:_237(_239?"touchstart":"mousedown"),move:_237(_239?"touchmove":"mousemove"),release:_237(_239?"touchend":"mouseup"),cancel:_239?_237("touchcancel"):_236.leave};return dojo.touch;});},"dojox/gfx/gradutils":function(){define(["./_base","dojo/_base/lang","./matrix","dojo/_base/Color"],function(g,lang,m,_23a){var _23b=g.gradutils={};function _23c(o,c){if(o<=0){return c[0].color;}var len=c.length;if(o>=1){return c[len-1].color;}for(var i=0;i<len;++i){var stop=c[i];if(stop.offset>=o){if(i){var prev=c[i-1];return _23a.blendColors(new _23a(prev.color),new _23a(stop.color),(o-prev.offset)/(stop.offset-prev.offset));}return stop.color;}}return c[len-1].color;};_23b.getColor=function(fill,pt){var o;if(fill){switch(fill.type){case "linear":var _23d=Math.atan2(fill.y2-fill.y1,fill.x2-fill.x1),_23e=m.rotate(-_23d),_23f=m.project(fill.x2-fill.x1,fill.y2-fill.y1),p=m.multiplyPoint(_23f,pt),pf1=m.multiplyPoint(_23f,fill.x1,fill.y1),pf2=m.multiplyPoint(_23f,fill.x2,fill.y2),_240=m.multiplyPoint(_23e,pf2.x-pf1.x,pf2.y-pf1.y).x;o=m.multiplyPoint(_23e,p.x-pf1.x,p.y-pf1.y).x/_240;break;case "radial":var dx=pt.x-fill.cx,dy=pt.y-fill.cy;o=Math.sqrt(dx*dx+dy*dy)/fill.r;break;}return _23c(o,fill.colors);}return new _23a(fill||[0,0,0,0]);};_23b.reverse=function(fill){if(fill){switch(fill.type){case "linear":case "radial":fill=lang.delegate(fill);if(fill.colors){var c=fill.colors,l=c.length,i=0,stop,n=fill.colors=new Array(c.length);for(;i<l;++i){stop=c[i];n[i]={offset:1-stop.offset,color:stop.color};}n.sort(function(a,b){return a.offset-b.offset;});}break;}}return fill;};return _23b;});},"dojo/string":function(){define(["./_base/kernel","./_base/lang"],function(dojo,lang){lang.getObject("string",true,dojo);dojo.string.rep=function(str,num){if(num<=0||!str){return "";}var buf=[];for(;;){if(num&1){buf.push(str);}if(!(num>>=1)){break;}str+=str;}return buf.join("");};dojo.string.pad=function(text,size,ch,end){if(!ch){ch="0";}var out=String(text),pad=dojo.string.rep(ch,Math.ceil((size-out.length)/ch.length));return end?out+pad:pad+out;};dojo.string.substitute=function(_241,map,_242,_243){_243=_243||dojo.global;_242=_242?lang.hitch(_243,_242):function(v){return v;};return _241.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,function(_244,key,_245){var _246=lang.getObject(key,false,map);if(_245){_246=lang.getObject(_245,false,_243).call(_243,_246,key);}return _242(_246,key).toString();});};dojo.string.trim=String.prototype.trim?lang.trim:function(str){str=str.replace(/^\s+/,"");for(var i=str.length-1;i>=0;i--){if(/\S/.test(str.charAt(i))){str=str.substring(0,i+1);break;}}return str;};return dojo.string;});},"dijit/registry":function(){define("dijit/registry",["dojo/_base/array","dojo/_base/sniff","dojo/_base/unload","dojo/_base/window","."],function(_247,has,_248,win,_249){var _24a={},hash={};var _24b={length:0,add:function(_24c){if(hash[_24c.id]){throw new Error("Tried to register widget with id=="+_24c.id+" but that id is already registered");}hash[_24c.id]=_24c;this.length++;},remove:function(id){if(hash[id]){delete hash[id];this.length--;}},byId:function(id){return typeof id=="string"?hash[id]:id;},byNode:function(node){return hash[node.getAttribute("widgetId")];},toArray:function(){var ar=[];for(var id in hash){ar.push(hash[id]);}return ar;},getUniqueId:function(_24d){var id;do{id=_24d+"_"+(_24d in _24a?++_24a[_24d]:_24a[_24d]=0);}while(hash[id]);return _249._scopeName=="dijit"?id:_249._scopeName+"_"+id;},findWidgets:function(root){var _24e=[];function _24f(root){for(var node=root.firstChild;node;node=node.nextSibling){if(node.nodeType==1){var _250=node.getAttribute("widgetId");if(_250){var _251=hash[_250];if(_251){_24e.push(_251);}}else{_24f(node);}}}};_24f(root);return _24e;},_destroyAll:function(){_249._curFocus=null;_249._prevFocus=null;_249._activeStack=[];_247.forEach(_24b.findWidgets(win.body()),function(_252){if(!_252._destroyed){if(_252.destroyRecursive){_252.destroyRecursive();}else{if(_252.destroy){_252.destroy();}}}});},getEnclosingWidget:function(node){while(node){var id=node.getAttribute&&node.getAttribute("widgetId");if(id){return hash[id];}node=node.parentNode;}return null;},_hash:hash};if(has("ie")){_248.addOnWindowUnload(function(){_24b._destroyAll();});}_249.registry=_24b;return _24b;});},"dojox/charting/plot2d/Lines":function(){define("dojox/charting/plot2d/Lines",["dojo/_base/declare","./Default"],function(_253,_254){return _253("dojox.charting.plot2d.Lines",_254,{constructor:function(){this.opt.lines=true;}});});},"dijit/_base/manager":function(){define("dijit/_base/manager",["dojo/_base/array","dojo/_base/config","../registry",".."],function(_255,_256,_257,_258){_255.forEach(["byId","getUniqueId","findWidgets","_destroyAll","byNode","getEnclosingWidget"],function(name){_258[name]=_257[name];});_258.defaultDuration=_256["defaultDuration"]||200;return _258;});},"dojox/charting/plot2d/StackedAreas":function(){define("dojox/charting/plot2d/StackedAreas",["dojo/_base/declare","./Stacked"],function(_259,_25a){return _259("dojox.charting.plot2d.StackedAreas",_25a,{constructor:function(){this.opt.lines=true;this.opt.areas=true;}});});},"dojox/charting/plot2d/Stacked":function(){define("dojox/charting/plot2d/Stacked",["dojo/_base/lang","dojo/_base/declare","dojo/_base/array","./Default","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/functional/sequence"],function(lang,_25b,arr,_25c,dc,df,dfr,dfs){var _25d=dfr.lambda("item.purgeGroup()");return _25b("dojox.charting.plot2d.Stacked",_25c,{getSeriesStats:function(){var _25e=dc.collectStackedStats(this.series);this._maxRunLength=_25e.hmax;return _25e;},render:function(dim,_25f){if(this._maxRunLength<=0){return this;}var acc=df.repeat(this._maxRunLength,"-> 0",0);for(var i=0;i<this.series.length;++i){var run=this.series[i];for(var j=0;j<run.data.length;++j){var v=run.data[j];if(v!==null){if(isNaN(v)){v=0;}acc[j]+=v;}}}if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_25f);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_25d);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,_260=this.events(),ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler);for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();var _261=t.next(this.opt.areas?"area":"line",[this.opt,run],true),s=run.group,_262,_263=arr.map(acc,function(v,i){return {x:ht(i+1)+_25f.l,y:dim.height-_25f.b-vt(v)};},this);var _264=this.opt.tension?dc.curve(_263,this.opt.tension):"";if(this.opt.areas){var _265=lang.clone(_263);if(this.opt.tension){var p=dc.curve(_265,this.opt.tension);p+=" L"+_263[_263.length-1].x+","+(dim.height-_25f.b)+" L"+_263[0].x+","+(dim.height-_25f.b)+" L"+_263[0].x+","+_263[0].y;run.dyn.fill=s.createPath(p).setFill(_261.series.fill).getFill();}else{_265.push({x:_263[_263.length-1].x,y:dim.height-_25f.b});_265.push({x:_263[0].x,y:dim.height-_25f.b});_265.push(_263[0]);run.dyn.fill=s.createPolyline(_265).setFill(_261.series.fill).getFill();}}if(this.opt.lines||this.opt.markers){if(_261.series.outline){_262=dc.makeStroke(_261.series.outline);_262.width=2*_262.width+_261.series.stroke.width;}}if(this.opt.markers){run.dyn.marker=_261.symbol;}var _266,_267,_268;if(_261.series.shadow&&_261.series.stroke){var _269=_261.series.shadow,_26a=arr.map(_263,function(c){return {x:c.x+_269.dx,y:c.y+_269.dy};});if(this.opt.lines){if(this.opt.tension){run.dyn.shadow=s.createPath(dc.curve(_26a,this.opt.tension)).setStroke(_269).getStroke();}else{run.dyn.shadow=s.createPolyline(_26a).setStroke(_269).getStroke();}}if(this.opt.markers){_269=_261.marker.shadow;_268=arr.map(_26a,function(c){return s.createPath("M"+c.x+" "+c.y+" "+_261.symbol).setStroke(_269).setFill(_269.color);},this);}}if(this.opt.lines){if(_262){if(this.opt.tension){run.dyn.outline=s.createPath(_264).setStroke(_262).getStroke();}else{run.dyn.outline=s.createPolyline(_263).setStroke(_262).getStroke();}}if(this.opt.tension){run.dyn.stroke=s.createPath(_264).setStroke(_261.series.stroke).getStroke();}else{run.dyn.stroke=s.createPolyline(_263).setStroke(_261.series.stroke).getStroke();}}if(this.opt.markers){_266=new Array(_263.length);_267=new Array(_263.length);_262=null;if(_261.marker.outline){_262=dc.makeStroke(_261.marker.outline);_262.width=2*_262.width+(_261.marker.stroke?_261.marker.stroke.width:0);}arr.forEach(_263,function(c,i){var path="M"+c.x+" "+c.y+" "+_261.symbol;if(_262){_267[i]=s.createPath(path).setStroke(_262);}_266[i]=s.createPath(path).setStroke(_261.marker.stroke).setFill(_261.marker.fill);},this);if(_260){var _26b=new Array(_266.length);arr.forEach(_266,function(s,i){var o={element:"marker",index:i,run:run,shape:s,outline:_267[i]||null,shadow:_268&&_268[i]||null,cx:_263[i].x,cy:_263[i].y,x:i+1,y:run.data[i]};this._connectEvents(o);_26b[i]=o;},this);this._eventSeries[run.name]=_26b;}else{delete this._eventSeries[run.name];}}run.dirty=false;for(var j=0;j<run.data.length;++j){var v=run.data[j];if(v!==null){if(isNaN(v)){v=0;}acc[j]-=v;}}}this.dirty=false;return this;}});});},"dojo/fx/easing":function(){define(["../_base/lang"],function(lang){var _26c={linear:function(n){return n;},quadIn:function(n){return Math.pow(n,2);},quadOut:function(n){return n*(n-2)*-1;},quadInOut:function(n){n=n*2;if(n<1){return Math.pow(n,2)/2;}return -1*((--n)*(n-2)-1)/2;},cubicIn:function(n){return Math.pow(n,3);},cubicOut:function(n){return Math.pow(n-1,3)+1;},cubicInOut:function(n){n=n*2;if(n<1){return Math.pow(n,3)/2;}n-=2;return (Math.pow(n,3)+2)/2;},quartIn:function(n){return Math.pow(n,4);},quartOut:function(n){return -1*(Math.pow(n-1,4)-1);},quartInOut:function(n){n=n*2;if(n<1){return Math.pow(n,4)/2;}n-=2;return -1/2*(Math.pow(n,4)-2);},quintIn:function(n){return Math.pow(n,5);},quintOut:function(n){return Math.pow(n-1,5)+1;},quintInOut:function(n){n=n*2;if(n<1){return Math.pow(n,5)/2;}n-=2;return (Math.pow(n,5)+2)/2;},sineIn:function(n){return -1*Math.cos(n*(Math.PI/2))+1;},sineOut:function(n){return Math.sin(n*(Math.PI/2));},sineInOut:function(n){return -1*(Math.cos(Math.PI*n)-1)/2;},expoIn:function(n){return (n==0)?0:Math.pow(2,10*(n-1));},expoOut:function(n){return (n==1)?1:(-1*Math.pow(2,-10*n)+1);},expoInOut:function(n){if(n==0){return 0;}if(n==1){return 1;}n=n*2;if(n<1){return Math.pow(2,10*(n-1))/2;}--n;return (-1*Math.pow(2,-10*n)+2)/2;},circIn:function(n){return -1*(Math.sqrt(1-Math.pow(n,2))-1);},circOut:function(n){n=n-1;return Math.sqrt(1-Math.pow(n,2));},circInOut:function(n){n=n*2;if(n<1){return -1/2*(Math.sqrt(1-Math.pow(n,2))-1);}n-=2;return 1/2*(Math.sqrt(1-Math.pow(n,2))+1);},backIn:function(n){var s=1.70158;return Math.pow(n,2)*((s+1)*n-s);},backOut:function(n){n=n-1;var s=1.70158;return Math.pow(n,2)*((s+1)*n+s)+1;},backInOut:function(n){var s=1.70158*1.525;n=n*2;if(n<1){return (Math.pow(n,2)*((s+1)*n-s))/2;}n-=2;return (Math.pow(n,2)*((s+1)*n+s)+2)/2;},elasticIn:function(n){if(n==0||n==1){return n;}var p=0.3;var s=p/4;n=n-1;return -1*Math.pow(2,10*n)*Math.sin((n-s)*(2*Math.PI)/p);},elasticOut:function(n){if(n==0||n==1){return n;}var p=0.3;var s=p/4;return Math.pow(2,-10*n)*Math.sin((n-s)*(2*Math.PI)/p)+1;},elasticInOut:function(n){if(n==0){return 0;}n=n*2;if(n==2){return 1;}var p=0.3*1.5;var s=p/4;if(n<1){n-=1;return -0.5*(Math.pow(2,10*n)*Math.sin((n-s)*(2*Math.PI)/p));}n-=1;return 0.5*(Math.pow(2,-10*n)*Math.sin((n-s)*(2*Math.PI)/p))+1;},bounceIn:function(n){return (1-_26c.bounceOut(1-n));},bounceOut:function(n){var s=7.5625;var p=2.75;var l;if(n<(1/p)){l=s*Math.pow(n,2);}else{if(n<(2/p)){n-=(1.5/p);l=s*Math.pow(n,2)+0.75;}else{if(n<(2.5/p)){n-=(2.25/p);l=s*Math.pow(n,2)+0.9375;}else{n-=(2.625/p);l=s*Math.pow(n,2)+0.984375;}}}return l;},bounceInOut:function(n){if(n<0.5){return _26c.bounceIn(n*2)/2;}return (_26c.bounceOut(n*2-1)/2)+0.5;}};lang.setObject("dojo.fx.easing",_26c);return _26c;});},"dojox/charting/action2d/Highlight":function(){define("dojox/charting/action2d/Highlight",["dojo/_base/kernel","dojo/_base/lang","dojo/_base/declare","dojo/_base/Color","dojo/_base/connect","dojox/color/_base","./PlotAction","dojo/fx/easing","dojox/gfx/fx"],function(dojo,lang,_26d,_26e,hub,c,_26f,dfe,dgf){var _270=100,_271=75,_272=50,cc=function(_273){return function(){return _273;};},hl=function(_274){var a=new c.Color(_274),x=a.toHsl();if(x.s==0){x.l=x.l<50?100:0;}else{x.s=_270;if(x.l<_272){x.l=_271;}else{if(x.l>_271){x.l=_272;}else{x.l=x.l-_272>_271-x.l?_272:_271;}}}return c.fromHsl(x);};return _26d("dojox.charting.action2d.Highlight",_26f,{defaultParams:{duration:400,easing:dfe.backOut},optionalParams:{highlight:"red"},constructor:function(_275,plot,_276){var a=_276&&_276.highlight;this.colorFun=a?(lang.isFunction(a)?a:cc(a)):hl;this.connect();},process:function(o){if(!o.shape||!(o.type in this.overOutEvents)){return;}var _277=o.run.name,_278=o.index,anim,_279,_27a;if(_277 in this.anim){anim=this.anim[_277][_278];}else{this.anim[_277]={};}if(anim){anim.action.stop(true);}else{var _27b=o.shape.getFill();if(!_27b||!(_27b instanceof _26e)){return;}this.anim[_277][_278]=anim={start:_27b,end:this.colorFun(_27b)};}var _27c=anim.start,end=anim.end;if(o.type=="onmouseout"){var t=_27c;_27c=end;end=t;}anim.action=dgf.animateFill({shape:o.shape,duration:this.duration,easing:this.easing,color:{start:_27c,end:end}});if(o.type=="onmouseout"){hub.connect(anim.action,"onEnd",this,function(){if(this.anim[_277]){delete this.anim[_277][_278];}});}anim.action.play();}});});},"dojox/color/Palette":function(){define("dojox/color/Palette",["dojo/_base/kernel","../main","dojo/_base/lang","dojo/_base/array","./_base"],function(dojo,_27d,lang,arr,dxc){dxc.Palette=function(base){this.colors=[];if(base instanceof dxc.Palette){this.colors=base.colors.slice(0);}else{if(base instanceof dxc.Color){this.colors=[null,null,base,null,null];}else{if(lang.isArray(base)){this.colors=arr.map(base.slice(0),function(item){if(lang.isString(item)){return new dxc.Color(item);}return item;});}else{if(lang.isString(base)){this.colors=[null,null,new dxc.Color(base),null,null];}}}}};function _27e(p,_27f,val){var ret=new dxc.Palette();ret.colors=[];arr.forEach(p.colors,function(item){var r=(_27f=="dr")?item.r+val:item.r,g=(_27f=="dg")?item.g+val:item.g,b=(_27f=="db")?item.b+val:item.b,a=(_27f=="da")?item.a+val:item.a;ret.colors.push(new dxc.Color({r:Math.min(255,Math.max(0,r)),g:Math.min(255,Math.max(0,g)),b:Math.min(255,Math.max(0,b)),a:Math.min(1,Math.max(0,a))}));});return ret;};function tCMY(p,_280,val){var ret=new dxc.Palette();ret.colors=[];arr.forEach(p.colors,function(item){var o=item.toCmy(),c=(_280=="dc")?o.c+val:o.c,m=(_280=="dm")?o.m+val:o.m,y=(_280=="dy")?o.y+val:o.y;ret.colors.push(dxc.fromCmy(Math.min(100,Math.max(0,c)),Math.min(100,Math.max(0,m)),Math.min(100,Math.max(0,y))));});return ret;};function _281(p,_282,val){var ret=new dxc.Palette();ret.colors=[];arr.forEach(p.colors,function(item){var o=item.toCmyk(),c=(_282=="dc")?o.c+val:o.c,m=(_282=="dm")?o.m+val:o.m,y=(_282=="dy")?o.y+val:o.y,k=(_282=="dk")?o.b+val:o.b;ret.colors.push(dxc.fromCmyk(Math.min(100,Math.max(0,c)),Math.min(100,Math.max(0,m)),Math.min(100,Math.max(0,y)),Math.min(100,Math.max(0,k))));});return ret;};function tHSL(p,_283,val){var ret=new dxc.Palette();ret.colors=[];arr.forEach(p.colors,function(item){var o=item.toHsl(),h=(_283=="dh")?o.h+val:o.h,s=(_283=="ds")?o.s+val:o.s,l=(_283=="dl")?o.l+val:o.l;ret.colors.push(dxc.fromHsl(h%360,Math.min(100,Math.max(0,s)),Math.min(100,Math.max(0,l))));});return ret;};function tHSV(p,_284,val){var ret=new dxc.Palette();ret.colors=[];arr.forEach(p.colors,function(item){var o=item.toHsv(),h=(_284=="dh")?o.h+val:o.h,s=(_284=="ds")?o.s+val:o.s,v=(_284=="dv")?o.v+val:o.v;ret.colors.push(dxc.fromHsv(h%360,Math.min(100,Math.max(0,s)),Math.min(100,Math.max(0,v))));});return ret;};function _285(val,low,high){return high-((high-val)*((high-low)/high));};lang.extend(dxc.Palette,{transform:function(_286){var fn=_27e;if(_286.use){var use=_286.use.toLowerCase();if(use.indexOf("hs")==0){if(use.charAt(2)=="l"){fn=tHSL;}else{fn=tHSV;}}else{if(use.indexOf("cmy")==0){if(use.charAt(3)=="k"){fn=_281;}else{fn=tCMY;}}}}else{if("dc" in _286||"dm" in _286||"dy" in _286){if("dk" in _286){fn=_281;}else{fn=tCMY;}}else{if("dh" in _286||"ds" in _286){if("dv" in _286){fn=tHSV;}else{fn=tHSL;}}}}var _287=this;for(var p in _286){if(p=="use"){continue;}_287=fn(_287,p,_286[p]);}return _287;},clone:function(){return new dxc.Palette(this);}});lang.mixin(dxc.Palette,{generators:{analogous:function(args){var high=args.high||60,low=args.low||18,base=lang.isString(args.base)?new dxc.Color(args.base):args.base,hsv=base.toHsv();var h=[(hsv.h+low+360)%360,(hsv.h+Math.round(low/2)+360)%360,hsv.h,(hsv.h-Math.round(high/2)+360)%360,(hsv.h-high+360)%360];var s1=Math.max(10,(hsv.s<=95)?hsv.s+5:(100-(hsv.s-95))),s2=(hsv.s>1)?hsv.s-1:21-hsv.s,v1=(hsv.v>=92)?hsv.v-9:Math.max(hsv.v+9,20),v2=(hsv.v<=90)?Math.max(hsv.v+5,20):(95+Math.ceil((hsv.v-90)/2)),s=[s1,s2,hsv.s,s1,s1],v=[v1,v2,hsv.v,v1,v2];return new dxc.Palette(arr.map(h,function(hue,i){return dxc.fromHsv(hue,s[i],v[i]);}));},monochromatic:function(args){var base=lang.isString(args.base)?new dxc.Color(args.base):args.base,hsv=base.toHsv();var s1=(hsv.s-30>9)?hsv.s-30:hsv.s+30,s2=hsv.s,v1=_285(hsv.v,20,100),v2=(hsv.v-20>20)?hsv.v-20:hsv.v+60,v3=(hsv.v-50>20)?hsv.v-50:hsv.v+30;return new dxc.Palette([dxc.fromHsv(hsv.h,s1,v1),dxc.fromHsv(hsv.h,s2,v3),base,dxc.fromHsv(hsv.h,s1,v3),dxc.fromHsv(hsv.h,s2,v2)]);},triadic:function(args){var base=lang.isString(args.base)?new dxc.Color(args.base):args.base,hsv=base.toHsv();var h1=(hsv.h+57+360)%360,h2=(hsv.h-157+360)%360,s1=(hsv.s>20)?hsv.s-10:hsv.s+10,s2=(hsv.s>90)?hsv.s-10:hsv.s+10,s3=(hsv.s>95)?hsv.s-5:hsv.s+5,v1=(hsv.v-20>20)?hsv.v-20:hsv.v+20,v2=(hsv.v-30>20)?hsv.v-30:hsv.v+30,v3=(hsv.v-30>70)?hsv.v-30:hsv.v+30;return new dxc.Palette([dxc.fromHsv(h1,s1,hsv.v),dxc.fromHsv(hsv.h,s2,v2),base,dxc.fromHsv(h2,s2,v1),dxc.fromHsv(h2,s3,v3)]);},complementary:function(args){var base=lang.isString(args.base)?new dxc.Color(args.base):args.base,hsv=base.toHsv();var h1=((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137,s1=Math.max(hsv.s-10,0),s2=_285(hsv.s,10,100),s3=Math.min(100,hsv.s+20),v1=Math.min(100,hsv.v+30),v2=(hsv.v>20)?hsv.v-30:hsv.v+30;return new dxc.Palette([dxc.fromHsv(hsv.h,s1,v1),dxc.fromHsv(hsv.h,s2,v2),base,dxc.fromHsv(h1,s3,v2),dxc.fromHsv(h1,hsv.s,hsv.v)]);},splitComplementary:function(args){var base=lang.isString(args.base)?new dxc.Color(args.base):args.base,_288=args.da||30,hsv=base.toHsv();var _289=((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137,h1=(_289-_288+360)%360,h2=(_289+_288)%360,s1=Math.max(hsv.s-10,0),s2=_285(hsv.s,10,100),s3=Math.min(100,hsv.s+20),v1=Math.min(100,hsv.v+30),v2=(hsv.v>20)?hsv.v-30:hsv.v+30;return new dxc.Palette([dxc.fromHsv(h1,s1,v1),dxc.fromHsv(h1,s2,v2),base,dxc.fromHsv(h2,s3,v2),dxc.fromHsv(h2,hsv.s,hsv.v)]);},compound:function(args){var base=lang.isString(args.base)?new dxc.Color(args.base):args.base,hsv=base.toHsv();var h1=((hsv.h*2)+18<360)?(hsv.h*2)+18:Math.floor(hsv.h/2)-18,h2=((hsv.h*2)+120<360)?(hsv.h*2)+120:Math.floor(hsv.h/2)-120,h3=((hsv.h*2)+99<360)?(hsv.h*2)+99:Math.floor(hsv.h/2)-99,s1=(hsv.s-40>10)?hsv.s-40:hsv.s+40,s2=(hsv.s-10>80)?hsv.s-10:hsv.s+10,s3=(hsv.s-25>10)?hsv.s-25:hsv.s+25,v1=(hsv.v-40>10)?hsv.v-40:hsv.v+40,v2=(hsv.v-20>80)?hsv.v-20:hsv.v+20,v3=Math.max(hsv.v,20);return new dxc.Palette([dxc.fromHsv(h1,s1,v1),dxc.fromHsv(h1,s2,v2),base,dxc.fromHsv(h2,s3,v3),dxc.fromHsv(h3,s2,v2)]);},shades:function(args){var base=lang.isString(args.base)?new dxc.Color(args.base):args.base,hsv=base.toHsv();var s=(hsv.s==100&&hsv.v==0)?0:hsv.s,v1=(hsv.v-50>20)?hsv.v-50:hsv.v+30,v2=(hsv.v-25>=20)?hsv.v-25:hsv.v+55,v3=(hsv.v-75>=20)?hsv.v-75:hsv.v+5,v4=Math.max(hsv.v-10,20);return new dxc.Palette([new dxc.fromHsv(hsv.h,s,v1),new dxc.fromHsv(hsv.h,s,v2),base,new dxc.fromHsv(hsv.h,s,v3),new dxc.fromHsv(hsv.h,s,v4)]);}},generate:function(base,type){if(lang.isFunction(type)){return type({base:base});}else{if(dxc.Palette.generators[type]){return dxc.Palette.generators[type]({base:base});}}throw new Error("dojox.color.Palette.generate: the specified generator ('"+type+"') does not exist.");}});return dxc.Palette;});},"dijit/a11y":function(){define("dijit/a11y",["dojo/_base/array","dojo/_base/config","dojo/_base/declare","dojo/dom","dojo/dom-attr","dojo/dom-style","dojo/_base/sniff","./_base/manager","."],function(_28a,_28b,_28c,dom,_28d,_28e,has,_28f,_290){var _291=(_290._isElementShown=function(elem){var s=_28e.get(elem);return (s.visibility!="hidden")&&(s.visibility!="collapsed")&&(s.display!="none")&&(_28d.get(elem,"type")!="hidden");});_290.hasDefaultTabStop=function(elem){switch(elem.nodeName.toLowerCase()){case "a":return _28d.has(elem,"href");case "area":case "button":case "input":case "object":case "select":case "textarea":return true;case "iframe":var body;try{var _292=elem.contentDocument;if("designMode" in _292&&_292.designMode=="on"){return true;}body=_292.body;}catch(e1){try{body=elem.contentWindow.document.body;}catch(e2){return false;}}return body&&(body.contentEditable=="true"||(body.firstChild&&body.firstChild.contentEditable=="true"));default:return elem.contentEditable=="true";}};var _293=(_290.isTabNavigable=function(elem){if(_28d.get(elem,"disabled")){return false;}else{if(_28d.has(elem,"tabIndex")){return _28d.get(elem,"tabIndex")>=0;}else{return _290.hasDefaultTabStop(elem);}}});_290._getTabNavigable=function(root){var _294,last,_295,_296,_297,_298,_299={};function _29a(node){return node&&node.tagName.toLowerCase()=="input"&&node.type&&node.type.toLowerCase()=="radio"&&node.name&&node.name.toLowerCase();};var _29b=function(_29c){for(var _29d=_29c.firstChild;_29d;_29d=_29d.nextSibling){if(_29d.nodeType!=1||(has("ie")&&_29d.scopeName!=="HTML")||!_291(_29d)){continue;}if(_293(_29d)){var _29e=_28d.get(_29d,"tabIndex");if(!_28d.has(_29d,"tabIndex")||_29e==0){if(!_294){_294=_29d;}last=_29d;}else{if(_29e>0){if(!_295||_29e<_296){_296=_29e;_295=_29d;}if(!_297||_29e>=_298){_298=_29e;_297=_29d;}}}var rn=_29a(_29d);if(_28d.get(_29d,"checked")&&rn){_299[rn]=_29d;}}if(_29d.nodeName.toUpperCase()!="SELECT"){_29b(_29d);}}};if(_291(root)){_29b(root);}function rs(node){return _299[_29a(node)]||node;};return {first:rs(_294),last:rs(last),lowest:rs(_295),highest:rs(_297)};};_290.getFirstInTabbingOrder=function(root){var _29f=_290._getTabNavigable(dom.byId(root));return _29f.lowest?_29f.lowest:_29f.first;};_290.getLastInTabbingOrder=function(root){var _2a0=_290._getTabNavigable(dom.byId(root));return _2a0.last?_2a0.last:_2a0.highest;};return {hasDefaultTabStop:_290.hasDefaultTabStop,isTabNavigable:_290.isTabNavigable,_getTabNavigable:_290._getTabNavigable,getFirstInTabbingOrder:_290.getFirstInTabbingOrder,getLastInTabbingOrder:_290.getLastInTabbingOrder};});},"dojox/charting/axis2d/Base":function(){define("dojox/charting/axis2d/Base",["dojo/_base/declare","../Element"],function(_2a1,_2a2){return _2a1("dojox.charting.axis2d.Base",_2a2,{constructor:function(_2a3,_2a4){this.vertical=_2a4&&_2a4.vertical;},clear:function(){return this;},initialized:function(){return false;},calculate:function(min,max,span){return this;},getScaler:function(){return null;},getTicks:function(){return null;},getOffsets:function(){return {l:0,r:0,t:0,b:0};},render:function(dim,_2a5){this.dirty=false;return this;}});});},"dojox/charting/plot2d/Grid":function(){define("dojox/charting/plot2d/Grid",["dojo/_base/lang","dojo/_base/declare","dojo/_base/connect","dojo/_base/array","../Element","./common","dojox/lang/utils","dojox/gfx/fx"],function(lang,_2a6,hub,arr,_2a7,dc,du,fx){return _2a6("dojox.charting.plot2d.Grid",_2a7,{defaultParams:{hAxis:"x",vAxis:"y",hMajorLines:true,hMinorLines:false,vMajorLines:true,vMinorLines:false,hStripes:"none",vStripes:"none",animate:null,enableCache:false},optionalParams:{},constructor:function(_2a8,_2a9){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_2a9);this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.dirty=true;this.animate=this.opt.animate;this.zoom=null,this.zoomQueue=[];this.lastWindow={vscale:1,hscale:1,xoffset:0,yoffset:0};if(this.opt.enableCache){this._lineFreePool=[];this._lineUsePool=[];}},clear:function(){this._hAxis=null;this._vAxis=null;this.dirty=true;return this;},setAxis:function(axis){if(axis){this[axis.vertical?"_vAxis":"_hAxis"]=axis;}return this;},addSeries:function(run){return this;},getSeriesStats:function(){return lang.delegate(dc.defaultStats);},initializeScalers:function(){return this;},isDirty:function(){return this.dirty||this._hAxis&&this._hAxis.dirty||this._vAxis&&this._vAxis.dirty;},performZoom:function(dim,_2aa){var vs=this._vAxis.scale||1,hs=this._hAxis.scale||1,_2ab=dim.height-_2aa.b,_2ac=this._hAxis.getScaler().bounds,_2ad=(_2ac.from-_2ac.lower)*_2ac.scale,_2ae=this._vAxis.getScaler().bounds,_2af=(_2ae.from-_2ae.lower)*_2ae.scale,_2b0=vs/this.lastWindow.vscale,_2b1=hs/this.lastWindow.hscale,_2b2=(this.lastWindow.xoffset-_2ad)/((this.lastWindow.hscale==1)?hs:this.lastWindow.hscale),_2b3=(_2af-this.lastWindow.yoffset)/((this.lastWindow.vscale==1)?vs:this.lastWindow.vscale),_2b4=this.group,anim=fx.animateTransform(lang.delegate({shape:_2b4,duration:1200,transform:[{name:"translate",start:[0,0],end:[_2aa.l*(1-_2b1),_2ab*(1-_2b0)]},{name:"scale",start:[1,1],end:[_2b1,_2b0]},{name:"original"},{name:"translate",start:[0,0],end:[_2b2,_2b3]}]},this.zoom));lang.mixin(this.lastWindow,{vscale:vs,hscale:hs,xoffset:_2ad,yoffset:_2af});this.zoomQueue.push(anim);hub.connect(anim,"onEnd",this,function(){this.zoom=null;this.zoomQueue.shift();if(this.zoomQueue.length>0){this.zoomQueue[0].play();}});if(this.zoomQueue.length==1){this.zoomQueue[0].play();}return this;},getRequiredColors:function(){return 0;},cleanGroup:function(){this.inherited(arguments);if(this.opt.enableCache){this._lineFreePool=this._lineFreePool.concat(this._lineUsePool);this._lineUsePool=[];}},createLine:function(_2b5,_2b6){var line;if(this.opt.enableCache&&this._lineFreePool.length>0){line=this._lineFreePool.pop();line.setShape(_2b6);_2b5.add(line);}else{line=_2b5.createLine(_2b6);}if(this.opt.enableCache){this._lineUsePool.push(line);}return line;},render:function(dim,_2b7){if(this.zoom){return this.performZoom(dim,_2b7);}this.dirty=this.isDirty();if(!this.dirty){return this;}this.cleanGroup();var s=this.group,ta=this.chart.theme.axis;try{var _2b8=this._vAxis.getScaler(),vt=_2b8.scaler.getTransformerFromModel(_2b8),_2b9=this._vAxis.getTicks();if(_2b9!=null){if(this.opt.hMinorLines){arr.forEach(_2b9.minor,function(tick){var y=dim.height-_2b7.b-vt(tick.value);var _2ba=this.createLine(s,{x1:_2b7.l,y1:y,x2:dim.width-_2b7.r,y2:y}).setStroke(ta.minorTick);if(this.animate){this._animateGrid(_2ba,"h",_2b7.l,_2b7.r+_2b7.l-dim.width);}},this);}if(this.opt.hMajorLines){arr.forEach(_2b9.major,function(tick){var y=dim.height-_2b7.b-vt(tick.value);var _2bb=this.createLine(s,{x1:_2b7.l,y1:y,x2:dim.width-_2b7.r,y2:y}).setStroke(ta.majorTick);if(this.animate){this._animateGrid(_2bb,"h",_2b7.l,_2b7.r+_2b7.l-dim.width);}},this);}}}catch(e){}try{var _2bc=this._hAxis.getScaler(),ht=_2bc.scaler.getTransformerFromModel(_2bc),_2b9=this._hAxis.getTicks();if(this!=null){if(_2b9&&this.opt.vMinorLines){arr.forEach(_2b9.minor,function(tick){var x=_2b7.l+ht(tick.value);var _2bd=this.createLine(s,{x1:x,y1:_2b7.t,x2:x,y2:dim.height-_2b7.b}).setStroke(ta.minorTick);if(this.animate){this._animateGrid(_2bd,"v",dim.height-_2b7.b,dim.height-_2b7.b-_2b7.t);}},this);}if(_2b9&&this.opt.vMajorLines){arr.forEach(_2b9.major,function(tick){var x=_2b7.l+ht(tick.value);var _2be=this.createLine(s,{x1:x,y1:_2b7.t,x2:x,y2:dim.height-_2b7.b}).setStroke(ta.majorTick);if(this.animate){this._animateGrid(_2be,"v",dim.height-_2b7.b,dim.height-_2b7.b-_2b7.t);}},this);}}}catch(e){}this.dirty=false;return this;},_animateGrid:function(_2bf,type,_2c0,size){var _2c1=type=="h"?[_2c0,0]:[0,_2c0];var _2c2=type=="h"?[1/size,1]:[1,1/size];fx.animateTransform(lang.delegate({shape:_2bf,duration:1200,transform:[{name:"translate",start:_2c1,end:[0,0]},{name:"scale",start:_2c2,end:[1,1]},{name:"original"}]},this.animate)).play();}});});},"dojox/gfx/utils":function(){define("dojox/gfx/utils",["dojo/_base/kernel","dojo/_base/lang","./_base","dojo/_base/html","dojo/_base/array","dojo/_base/window","dojo/_base/json","dojo/_base/Deferred","dojo/_base/sniff","require","dojo/_base/config"],function(_2c3,lang,g,html,arr,win,_2c4,_2c5,has,_2c6,_2c7){var gu=g.utils={};lang.mixin(gu,{forEach:function(_2c8,f,o){o=o||win.global;f.call(o,_2c8);if(_2c8 instanceof g.Surface||_2c8 instanceof g.Group){arr.forEach(_2c8.children,function(_2c9){gu.forEach(_2c9,f,o);});}},serialize:function(_2ca){var t={},v,_2cb=_2ca instanceof g.Surface;if(_2cb||_2ca instanceof g.Group){t.children=arr.map(_2ca.children,gu.serialize);if(_2cb){return t.children;}}else{t.shape=_2ca.getShape();}if(_2ca.getTransform){v=_2ca.getTransform();if(v){t.transform=v;}}if(_2ca.getStroke){v=_2ca.getStroke();if(v){t.stroke=v;}}if(_2ca.getFill){v=_2ca.getFill();if(v){t.fill=v;}}if(_2ca.getFont){v=_2ca.getFont();if(v){t.font=v;}}return t;},toJson:function(_2cc,_2cd){return _2c4.toJson(gu.serialize(_2cc),_2cd);},deserialize:function(_2ce,_2cf){if(_2cf instanceof Array){return arr.map(_2cf,lang.hitch(null,gu.deserialize,_2ce));}var _2d0=("shape" in _2cf)?_2ce.createShape(_2cf.shape):_2ce.createGroup();if("transform" in _2cf){_2d0.setTransform(_2cf.transform);}if("stroke" in _2cf){_2d0.setStroke(_2cf.stroke);}if("fill" in _2cf){_2d0.setFill(_2cf.fill);}if("font" in _2cf){_2d0.setFont(_2cf.font);}if("children" in _2cf){arr.forEach(_2cf.children,lang.hitch(null,gu.deserialize,_2d0));}return _2d0;},fromJson:function(_2d1,json){return gu.deserialize(_2d1,_2c4.fromJson(json));},toSvg:function(_2d2){var _2d3=new _2c5();if(g.renderer==="svg"){try{var svg=gu._cleanSvg(gu._innerXML(_2d2.rawNode));_2d3.callback(svg);}catch(e){_2d3.errback(e);}}else{if(!gu._initSvgSerializerDeferred){gu._initSvgSerializer();}var _2d4=gu.toJson(_2d2);var _2d5=function(){try{var sDim=_2d2.getDimensions();var _2d6=sDim.width;var _2d7=sDim.height;var node=gu._gfxSvgProxy.document.createElement("div");gu._gfxSvgProxy.document.body.appendChild(node);win.withDoc(gu._gfxSvgProxy.document,function(){html.style(node,"width",_2d6);html.style(node,"height",_2d7);},this);var ts=gu._gfxSvgProxy[dojox._scopeName].gfx.createSurface(node,_2d6,_2d7);var draw=function(_2d8){try{gu._gfxSvgProxy[dojox._scopeName].gfx.utils.fromJson(_2d8,_2d4);var svg=gu._cleanSvg(node.innerHTML);_2d8.clear();_2d8.destroy();gu._gfxSvgProxy.document.body.removeChild(node);_2d3.callback(svg);}catch(e){_2d3.errback(e);}};ts.whenLoaded(null,draw);}catch(ex){_2d3.errback(ex);}};if(gu._initSvgSerializerDeferred.fired>0){_2d5();}else{gu._initSvgSerializerDeferred.addCallback(_2d5);}}return _2d3;},_gfxSvgProxy:null,_initSvgSerializerDeferred:null,_svgSerializerInitialized:function(){gu._initSvgSerializerDeferred.callback(true);},_initSvgSerializer:function(){if(!gu._initSvgSerializerDeferred){gu._initSvgSerializerDeferred=new _2c5();var f=win.doc.createElement("iframe");html.style(f,{display:"none",position:"absolute",width:"1em",height:"1em",top:"-10000px"});var intv;if(has("ie")){f.onreadystatechange=function(){if(f.contentWindow.document.readyState=="complete"){f.onreadystatechange=function(){};intv=setInterval(function(){if(f.contentWindow[_2c3.scopeMap["dojo"][1]._scopeName]&&f.contentWindow[_2c3.scopeMap["dojox"][1]._scopeName].gfx&&f.contentWindow[_2c3.scopeMap["dojox"][1]._scopeName].gfx.utils){clearInterval(intv);f.contentWindow.parent[_2c3.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy=f.contentWindow;f.contentWindow.parent[_2c3.scopeMap["dojox"][1]._scopeName].gfx.utils._svgSerializerInitialized();}},50);}};}else{f.onload=function(){f.onload=function(){};intv=setInterval(function(){if(f.contentWindow[_2c3.scopeMap["dojo"][1]._scopeName]&&f.contentWindow[_2c3.scopeMap["dojox"][1]._scopeName].gfx&&f.contentWindow[_2c3.scopeMap["dojox"][1]._scopeName].gfx.utils){clearInterval(intv);f.contentWindow.parent[_2c3.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy=f.contentWindow;f.contentWindow.parent[_2c3.scopeMap["dojox"][1]._scopeName].gfx.utils._svgSerializerInitialized();}},50);};}var uri=(_2c7["dojoxGfxSvgProxyFrameUrl"]||_2c6.toUrl("dojox/gfx/resources/gfxSvgProxyFrame.html"));f.setAttribute("src",uri.toString());win.body().appendChild(f);}},_innerXML:function(node){if(node.innerXML){return node.innerXML;}else{if(node.xml){return node.xml;}else{if(typeof XMLSerializer!="undefined"){return (new XMLSerializer()).serializeToString(node);}}}return null;},_cleanSvg:function(svg){if(svg){if(svg.indexOf("xmlns=\"http://www.w3.org/2000/svg\"")==-1){svg=svg.substring(4,svg.length);svg="<svg xmlns=\"http://www.w3.org/2000/svg\""+svg;}if(svg.indexOf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"")==-1){svg=svg.substring(4,svg.length);svg="<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\""+svg;}if(svg.indexOf("xlink:href")===-1){svg=svg.replace(/href\s*=/g,"xlink:href=");}svg=svg.replace(/\bdojoGfx\w*\s*=\s*(['"])\w*\1/g,"");svg=svg.replace(/\b__gfxObject__\s*=\s*(['"])\w*\1/g,"");svg=svg.replace(/[=]([^"']+?)(\s|>)/g,"=\"$1\"$2");}return svg;}});return gu;});},"dojox/lang/functional/fold":function(){define("dojox/lang/functional/fold",["dojo/_base/lang","dojo/_base/array","dojo/_base/window","./lambda"],function(lang,arr,win,df){var _2d9={};lang.mixin(df,{foldl:function(a,f,z,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var i,n;if(lang.isArray(a)){for(i=0,n=a.length;i<n;z=f.call(o,z,a[i],i,a),++i){}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){for(i=0;a.hasNext();z=f.call(o,z,a.next(),i++,a)){}}else{for(i in a){if(!(i in _2d9)){z=f.call(o,z,a[i],i,a);}}}}return z;},foldl1:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var z,i,n;if(lang.isArray(a)){z=a[0];for(i=1,n=a.length;i<n;z=f.call(o,z,a[i],i,a),++i){}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){if(a.hasNext()){z=a.next();for(i=1;a.hasNext();z=f.call(o,z,a.next(),i++,a)){}}}else{var _2da=true;for(i in a){if(!(i in _2d9)){if(_2da){z=a[i];_2da=false;}else{z=f.call(o,z,a[i],i,a);}}}}}return z;},foldr:function(a,f,z,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);for(var i=a.length;i>0;--i,z=f.call(o,z,a[i],i,a)){}return z;},foldr1:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var n=a.length,z=a[n-1],i=n-1;for(;i>0;--i,z=f.call(o,z,a[i],i,a)){}return z;},reduce:function(a,f,z){return arguments.length<3?df.foldl1(a,f):df.foldl(a,f,z);},reduceRight:function(a,f,z){return arguments.length<3?df.foldr1(a,f):df.foldr(a,f,z);},unfold:function(pr,f,g,z,o){o=o||win.global;f=df.lambda(f);g=df.lambda(g);pr=df.lambda(pr);var t=[];for(;!pr.call(o,z);t.push(f.call(o,z)),z=g.call(o,z)){}return t;}});});},"url:dijit/templates/Tooltip.html":"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n></div>\n","dojox/charting/plot2d/Spider":function(){define("dojox/charting/plot2d/Spider",["dojo/_base/lang","dojo/_base/declare","dojo/_base/connect","dojo/_base/html","dojo/_base/array","dojo/dom-geometry","dojo/_base/fx","dojo/fx","dojo/_base/sniff","../Element","./_PlotEvents","dojo/_base/Color","dojox/color/_base","./common","../axis2d/common","../scaler/primitive","dojox/gfx","dojox/gfx/matrix","dojox/gfx/fx","dojox/lang/functional","dojox/lang/utils","dojo/fx/easing"],function(lang,_2db,hub,html,arr,_2dc,_2dd,_2de,has,_2df,_2e0,_2e1,_2e2,dc,da,_2e3,g,m,_2e4,df,du,_2e5){var _2e6=0.2;var _2e7=_2db("dojox.charting.plot2d.Spider",[_2df,_2e0],{defaultParams:{labels:true,ticks:false,fixed:true,precision:1,labelOffset:-10,labelStyle:"default",htmlLabels:true,startAngle:-90,divisions:3,axisColor:"",axisWidth:0,spiderColor:"",spiderWidth:0,seriesWidth:0,seriesFillAlpha:0.2,spiderOrigin:0.16,markerSize:3,spiderType:"polygon",animationType:_2e5.backOut,axisTickFont:"",axisTickFontColor:"",axisFont:"",axisFontColor:""},optionalParams:{radius:0,font:"",fontColor:""},constructor:function(_2e8,_2e9){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_2e9);du.updateWithPattern(this.opt,_2e9,this.optionalParams);this.series=[];this.dyn=[];this.datas={};this.labelKey=[];this.oldSeriePoints={};this.animations={};},clear:function(){this.dirty=true;this.dyn=[];this.series=[];this.datas={};this.labelKey=[];this.oldSeriePoints={};this.animations={};return this;},setAxis:function(axis){return this;},addSeries:function(run){var _2ea=false;this.series.push(run);for(var key in run.data){var val=run.data[key],data=this.datas[key];if(data){data.vlist.push(val);data.min=Math.min(data.min,val);data.max=Math.max(data.max,val);}else{this.datas[key]={min:val,max:val,vlist:[val]};}}if(this.labelKey.length<=0){for(var key in run.data){this.labelKey.push(key);}}return this;},getSeriesStats:function(){return dc.collectSimpleStats(this.series);},calculateAxes:function(dim){this.initializeScalers(dim,this.getSeriesStats());return this;},getRequiredColors:function(){return this.series.length;},initializeScalers:function(dim,_2eb){if(this._hAxis){if(!this._hAxis.initialized()){this._hAxis.calculate(_2eb.hmin,_2eb.hmax,dim.width);}this._hScaler=this._hAxis.getScaler();}else{this._hScaler=_2e3.buildScaler(_2eb.hmin,_2eb.hmax,dim.width);}if(this._vAxis){if(!this._vAxis.initialized()){this._vAxis.calculate(_2eb.vmin,_2eb.vmax,dim.height);}this._vScaler=this._vAxis.getScaler();}else{this._vScaler=_2e3.buildScaler(_2eb.vmin,_2eb.vmax,dim.height);}return this;},render:function(dim,_2ec){if(!this.dirty){return this;}this.dirty=false;this.cleanGroup();var s=this.group,t=this.chart.theme;this.resetEvents();if(!this.series||!this.series.length){return this;}var o=this.opt,ta=t.axis,rx=(dim.width-_2ec.l-_2ec.r)/2,ry=(dim.height-_2ec.t-_2ec.b)/2,r=Math.min(rx,ry),_2ed=o.font||(ta.majorTick&&ta.majorTick.font)||(ta.tick&&ta.tick.font)||"normal normal normal 7pt Tahoma",_2ee=o.axisFont||(ta.tick&&ta.tick.titleFont)||"normal normal normal 11pt Tahoma",_2ef=o.axisTickFontColor||(ta.majorTick&&ta.majorTick.fontColor)||(ta.tick&&ta.tick.fontColor)||"silver",_2f0=o.axisFontColor||(ta.tick&&ta.tick.titleFontColor)||"black",_2f1=o.axisColor||(ta.tick&&ta.tick.axisColor)||"silver",_2f2=o.spiderColor||(ta.tick&&ta.tick.spiderColor)||"silver",_2f3=o.axisWidth||(ta.stroke&&ta.stroke.width)||2,_2f4=o.spiderWidth||(ta.stroke&&ta.stroke.width)||2,_2f5=o.seriesWidth||(ta.stroke&&ta.stroke.width)||2,_2f6=g.normalizedLength(g.splitFontString(_2ee).size),_2f7=m._degToRad(o.startAngle),_2f8=_2f7,step,_2f9,_2fa,_2fb,_2fc,_2fd,_2fe,_2ff,_300,_301,_302,ro=o.spiderOrigin,dv=o.divisions>=3?o.divisions:3,ms=o.markerSize,spt=o.spiderType,at=o.animationType,_303=o.labelOffset<-10?o.labelOffset:-10,_304=0.2;if(o.labels){_2fb=arr.map(this.series,function(s){return s.name;},this);_2fc=df.foldl1(df.map(_2fb,function(_305,i){var font=t.series.font;return g._base._getTextBox(_305,{font:font}).w;},this),"Math.max(a, b)")/2;r=Math.min(rx-2*_2fc,ry-_2f6)+_303;_2fd=r-_303;}if("radius" in o){r=o.radius;_2fd=r-_303;}r/=(1+_304);var _306={cx:_2ec.l+rx,cy:_2ec.t+ry,r:r};for(var i=this.series.length-1;i>=0;i--){var _307=this.series[i];if(!this.dirty&&!_307.dirty){t.skip();continue;}_307.cleanGroup();var run=_307.data;if(run!==null){var len=this._getObjectLength(run);if(!_2fe||_2fe.length<=0){_2fe=[],_2ff=[],_302=[];this._buildPoints(_2fe,len,_306,r,_2f8,true);this._buildPoints(_2ff,len,_306,r*ro,_2f8,true);this._buildPoints(_302,len,_306,_2fd,_2f8);if(dv>2){_300=[],_301=[];for(var j=0;j<dv-2;j++){_300[j]=[];this._buildPoints(_300[j],len,_306,r*(ro+(1-ro)*(j+1)/(dv-1)),_2f8,true);_301[j]=r*(ro+(1-ro)*(j+1)/(dv-1));}}}}}var _308=s.createGroup(),_309={color:_2f1,width:_2f3},_30a={color:_2f2,width:_2f4};for(var j=_2fe.length-1;j>=0;--j){var _30b=_2fe[j],st={x:_30b.x+(_30b.x-_306.cx)*_304,y:_30b.y+(_30b.y-_306.cy)*_304},nd={x:_30b.x+(_30b.x-_306.cx)*_304/2,y:_30b.y+(_30b.y-_306.cy)*_304/2};_308.createLine({x1:_306.cx,y1:_306.cy,x2:st.x,y2:st.y}).setStroke(_309);this._drawArrow(_308,st,nd,_309);}var _30c=s.createGroup();for(var j=_302.length-1;j>=0;--j){var _30b=_302[j],_30d=g._base._getTextBox(this.labelKey[j],{font:_2ee}).w||0,_30e=this.opt.htmlLabels&&g.renderer!="vml"?"html":"gfx",elem=da.createText[_30e](this.chart,_30c,(!_2dc.isBodyLtr()&&_30e=="html")?(_30b.x+_30d-dim.width):_30b.x,_30b.y,"middle",this.labelKey[j],_2ee,_2f0);if(this.opt.htmlLabels){this.htmlElements.push(elem);}}var _30f=s.createGroup();if(spt=="polygon"){_30f.createPolyline(_2fe).setStroke(_30a);_30f.createPolyline(_2ff).setStroke(_30a);if(_300.length>0){for(var j=_300.length-1;j>=0;--j){_30f.createPolyline(_300[j]).setStroke(_30a);}}}else{var _310=this._getObjectLength(this.datas);_30f.createCircle({cx:_306.cx,cy:_306.cy,r:r}).setStroke(_30a);_30f.createCircle({cx:_306.cx,cy:_306.cy,r:r*ro}).setStroke(_30a);if(_301.length>0){for(var j=_301.length-1;j>=0;--j){_30f.createCircle({cx:_306.cx,cy:_306.cy,r:_301[j]}).setStroke(_30a);}}}var _311=s.createGroup(),len=this._getObjectLength(this.datas),k=0;for(var key in this.datas){var data=this.datas[key],min=data.min,max=data.max,_312=max-min,end=_2f8+2*Math.PI*k/len;for(var i=0;i<dv;i++){var text=min+_312*i/(dv-1),_30b=this._getCoordinate(_306,r*(ro+(1-ro)*i/(dv-1)),end);text=this._getLabel(text);var _30d=g._base._getTextBox(text,{font:_2ed}).w||0,_30e=this.opt.htmlLabels&&g.renderer!="vml"?"html":"gfx";if(this.opt.htmlLabels){this.htmlElements.push(da.createText[_30e](this.chart,_311,(!_2dc.isBodyLtr()&&_30e=="html")?(_30b.x+_30d-dim.width):_30b.x,_30b.y,"start",text,_2ed,_2ef));}}k++;}this.chart.seriesShapes={};var _313=[];for(var i=this.series.length-1;i>=0;i--){var _307=this.series[i],run=_307.data;if(run!==null){var _314=[],k=0,_315=[];for(var key in run){var data=this.datas[key],min=data.min,max=data.max,_312=max-min,_316=run[key],end=_2f8+2*Math.PI*k/len,_30b=this._getCoordinate(_306,r*(ro+(1-ro)*(_316-min)/_312),end);_314.push(_30b);_315.push({sname:_307.name,key:key,data:_316});k++;}_314[_314.length]=_314[0];_315[_315.length]=_315[0];var _317=this._getBoundary(_314),_318=t.next("spider",[o,_307]),ts=_307.group,f=g.normalizeColor(_318.series.fill),sk={color:_318.series.fill,width:_2f5};f.a=o.seriesFillAlpha;_307.dyn={fill:f,stroke:sk};var osps=this.oldSeriePoints[_307.name];var cs=this._createSeriesEntry(ts,(osps||_2ff),_314,f,sk,r,ro,ms,at);this.chart.seriesShapes[_307.name]=cs;this.oldSeriePoints[_307.name]=_314;var po={element:"spider_poly",index:i,id:"spider_poly_"+_307.name,run:_307,plot:this,shape:cs.poly,parent:ts,brect:_317,cx:_306.cx,cy:_306.cy,cr:r,f:f,s:s};this._connectEvents(po);var so={element:"spider_plot",index:i,id:"spider_plot_"+_307.name,run:_307,plot:this,shape:_307.group};this._connectEvents(so);arr.forEach(cs.circles,function(c,i){var _319=c.getShape(),co={element:"spider_circle",index:i,id:"spider_circle_"+_307.name+i,run:_307,plot:this,shape:c,parent:ts,tdata:_315[i],cx:_314[i].x,cy:_314[i].y,f:f,s:s};this._connectEvents(co);},this);}}return this;},_createSeriesEntry:function(ts,osps,sps,f,sk,r,ro,ms,at){var _31a=ts.createPolyline(osps).setFill(f).setStroke(sk),_31b=[];for(var j=0;j<osps.length;j++){var _31c=osps[j],cr=ms;var _31d=ts.createCircle({cx:_31c.x,cy:_31c.y,r:cr}).setFill(f).setStroke(sk);_31b.push(_31d);}var _31e=arr.map(sps,function(np,j){var sp=osps[j],anim=new _2dd.Animation({duration:1000,easing:at,curve:[sp.y,np.y]});var spl=_31a,sc=_31b[j];hub.connect(anim,"onAnimate",function(y){var _31f=spl.getShape();_31f.points[j].y=y;spl.setShape(_31f);var _320=sc.getShape();_320.cy=y;sc.setShape(_320);});return anim;});var _321=arr.map(sps,function(np,j){var sp=osps[j],anim=new _2dd.Animation({duration:1000,easing:at,curve:[sp.x,np.x]});var spl=_31a,sc=_31b[j];hub.connect(anim,"onAnimate",function(x){var _322=spl.getShape();_322.points[j].x=x;spl.setShape(_322);var _323=sc.getShape();_323.cx=x;sc.setShape(_323);});return anim;});var _324=_2de.combine(_31e.concat(_321));_324.play();return {group:ts,poly:_31a,circles:_31b};},plotEvent:function(o){var _325=o.id?o.id:"default",a;if(_325 in this.animations){a=this.animations[_325];a.anim&&a.anim.stop(true);}else{a=this.animations[_325]={};}if(o.element=="spider_poly"){if(!a.color){var _326=o.shape.getFill();if(!_326||!(_326 instanceof _2e1)){return;}a.color={start:_326,end:_327(_326)};}var _328=a.color.start,end=a.color.end;if(o.type=="onmouseout"){var t=_328;_328=end;end=t;}a.anim=_2e4.animateFill({shape:o.shape,duration:800,easing:_2e5.backOut,color:{start:_328,end:end}});a.anim.play();}else{if(o.element=="spider_circle"){var init,_329,_32a=1.5;if(o.type=="onmouseover"){init=m.identity;_329=_32a;var _32b={type:"rect"};_32b.x=o.cx;_32b.y=o.cy;_32b.width=_32b.height=1;var lt=html.coords(this.chart.node,true);_32b.x+=lt.x;_32b.y+=lt.y;_32b.x=Math.round(_32b.x);_32b.y=Math.round(_32b.y);_32b.width=Math.ceil(_32b.width);_32b.height=Math.ceil(_32b.height);this.aroundRect=_32b;var _32c=["after","before"];dc.doIfLoaded("dijit/Tooltip",dojo.hitch(this,function(_32d){_32d.show(o.tdata.sname+"<br/>"+o.tdata.key+"<br/>"+o.tdata.data,this.aroundRect,_32c);}));}else{init=m.scaleAt(_32a,o.cx,o.cy);_329=1/_32a;dc.doIfLoaded("dijit/Tooltip",dojo.hitch(this,function(_32e){this.aroundRect&&_32e.hide(this.aroundRect);}));}var cs=o.shape.getShape(),init=m.scaleAt(_32a,cs.cx,cs.cy),_32f={shape:o.shape,duration:200,easing:_2e5.backOut,transform:[{name:"scaleAt",start:[1,cs.cx,cs.cy],end:[_329,cs.cx,cs.cy]},init]};a.anim=_2e4.animateTransform(_32f);a.anim.play();}else{if(o.element=="spider_plot"){if(o.type=="onmouseover"&&!has("ie")){o.shape.moveToFront();}}}}},_getBoundary:function(_330){var xmax=_330[0].x,xmin=_330[0].x,ymax=_330[0].y,ymin=_330[0].y;for(var i=0;i<_330.length;i++){var _331=_330[i];xmax=Math.max(_331.x,xmax);ymax=Math.max(_331.y,ymax);xmin=Math.min(_331.x,xmin);ymin=Math.min(_331.y,ymin);}return {x:xmin,y:ymin,width:xmax-xmin,height:ymax-ymin};},_drawArrow:function(s,_332,end,_333){var len=Math.sqrt(Math.pow(end.x-_332.x,2)+Math.pow(end.y-_332.y,2)),sin=(end.y-_332.y)/len,cos=(end.x-_332.x)/len,_334={x:end.x+(len/3)*(-sin),y:end.y+(len/3)*cos},_335={x:end.x+(len/3)*sin,y:end.y+(len/3)*(-cos)};s.createPolyline([_332,_334,_335]).setFill(_333.color).setStroke(_333);},_buildPoints:function(_336,_337,_338,_339,_33a,_33b){for(var i=0;i<_337;i++){var end=_33a+2*Math.PI*i/_337;_336.push(this._getCoordinate(_338,_339,end));}if(_33b){_336.push(this._getCoordinate(_338,_339,_33a+2*Math.PI));}},_getCoordinate:function(_33c,_33d,_33e){return {x:_33c.cx+_33d*Math.cos(_33e),y:_33c.cy+_33d*Math.sin(_33e)};},_getObjectLength:function(obj){var _33f=0;if(lang.isObject(obj)){for(var key in obj){_33f++;}}return _33f;},_getLabel:function(_340){return dc.getLabel(_340,this.opt.fixed,this.opt.precision);}});function _327(_341){var a=new _2e2.Color(_341),x=a.toHsl();if(x.s==0){x.l=x.l<50?100:0;}else{x.s=100;if(x.l<50){x.l=75;}else{if(x.l>75){x.l=50;}else{x.l=x.l-50>75-x.l?50:75;}}}var _341=_2e2.fromHsl(x);_341.a=0.7;return _341;};return _2e7;});},"dojox/charting/plot2d/StackedBars":function(){define("dojox/charting/plot2d/StackedBars",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","./Bars","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/functional/sequence"],function(lang,arr,_342,Bars,dc,df,dfr,dfs){var _343=dfr.lambda("item.purgeGroup()");return _342("dojox.charting.plot2d.StackedBars",Bars,{getSeriesStats:function(){var _344=dc.collectStackedStats(this.series),t;this._maxRunLength=_344.hmax;_344.hmin-=0.5;_344.hmax+=0.5;t=_344.hmin,_344.hmin=_344.vmin,_344.vmin=t;t=_344.hmax,_344.hmax=_344.vmax,_344.vmax=t;return _344;},render:function(dim,_345){if(this._maxRunLength<=0){return this;}var acc=df.repeat(this._maxRunLength,"-> 0",0);for(var i=0;i<this.series.length;++i){var run=this.series[i];for(var j=0;j<run.data.length;++j){var _346=run.data[j];if(_346!==null){var v=typeof _346=="number"?_346:_346.y;if(isNaN(v)){v=0;}acc[j]+=v;}}}if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_345);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_343);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,f,gap,_347,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_348=this.events();f=dc.calculateBarSize(this._vScaler.bounds.scale,this.opt);gap=f.gap;_347=f.size;for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();var _349=t.next("bar",[this.opt,run]),s=run.group,_34a=new Array(acc.length);for(var j=0;j<acc.length;++j){var _346=run.data[j];if(_346!==null){var v=acc[j],_34b=ht(v),_34c=typeof _346!="number"?t.addMixin(_349,"bar",_346,true):t.post(_349,"bar");if(_34b>=0&&_347>=1){var rect={x:_345.l,y:dim.height-_345.b-vt(j+1.5)+gap,width:_34b,height:_347};var _34d=this._plotFill(_34c.series.fill,dim,_345);_34d=this._shapeFill(_34d,rect);var _34e=s.createRect(rect).setFill(_34d).setStroke(_34c.series.stroke);run.dyn.fill=_34e.getFill();run.dyn.stroke=_34e.getStroke();if(_348){var o={element:"bar",index:j,run:run,shape:_34e,x:v,y:j+1.5};this._connectEvents(o);_34a[j]=o;}if(this.animate){this._animateBar(_34e,_345.l,-_34b);}}}}this._eventSeries[run.name]=_34a;run.dirty=false;for(var j=0;j<run.data.length;++j){var _346=run.data[j];if(_346!==null){var v=typeof _346=="number"?_346:_346.y;if(isNaN(v)){v=0;}acc[j]-=v;}}}this.dirty=false;return this;}});});},"dojox/charting/themes/GreySkies":function(){define("dojox/charting/themes/GreySkies",["../Theme","./common"],function(_34f,_350){_350.GreySkies=new _34f(_34f._def);return _350.GreySkies;});},"dojox/charting/plot2d/Columns":function(){define("dojox/charting/plot2d/Columns",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","./Base","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils","dojox/gfx/fx"],function(lang,arr,_351,Base,dc,df,dfr,du,fx){var _352=dfr.lambda("item.purgeGroup()");return _351("dojox.charting.plot2d.Columns",Base,{defaultParams:{hAxis:"x",vAxis:"y",gap:0,animate:null,enableCache:false},optionalParams:{minBarSize:1,maxBarSize:1,stroke:{},outline:{},shadow:{},fill:{},font:"",fontColor:""},constructor:function(_353,_354){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_354);du.updateWithPattern(this.opt,_354,this.optionalParams);this.series=[];this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.animate=this.opt.animate;},getSeriesStats:function(){var _355=dc.collectSimpleStats(this.series);_355.hmin-=0.5;_355.hmax+=0.5;return _355;},createRect:function(run,_356,_357){var rect;if(this.opt.enableCache&&run._rectFreePool.length>0){rect=run._rectFreePool.pop();rect.setShape(_357);_356.add(rect);}else{rect=_356.createRect(_357);}if(this.opt.enableCache){run._rectUsePool.push(rect);}return rect;},render:function(dim,_358){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_358);}var t=this.getSeriesStats();this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_352);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,f,gap,_359,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_35a=Math.max(0,this._vScaler.bounds.lower),_35b=vt(_35a),min=Math.max(0,Math.floor(this._hScaler.bounds.from-1)),max=Math.ceil(this._hScaler.bounds.to),_35c=this.events();f=dc.calculateBarSize(this._hScaler.bounds.scale,this.opt);gap=f.gap;_359=f.size;for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();if(this.opt.enableCache){run._rectFreePool=(run._rectFreePool?run._rectFreePool:[]).concat(run._rectUsePool?run._rectUsePool:[]);run._rectUsePool=[];}var _35d=t.next("column",[this.opt,run]),s=run.group,_35e=new Array(run.data.length);var l=Math.min(run.data.length,max);for(var j=min;j<l;++j){var _35f=run.data[j];if(_35f!==null){var v=typeof _35f=="number"?_35f:_35f.y,vv=vt(v),_360=vv-_35b,h=Math.abs(_360),_361=typeof _35f!="number"?t.addMixin(_35d,"column",_35f,true):t.post(_35d,"column");if(_359>=1&&h>=0){var rect={x:_358.l+ht(j+0.5)+gap,y:dim.height-_358.b-(v>_35a?vv:_35b),width:_359,height:h};var _362=this._plotFill(_361.series.fill,dim,_358);_362=this._shapeFill(_362,rect);var _363=this.createRect(run,s,rect).setFill(_362).setStroke(_361.series.stroke);run.dyn.fill=_363.getFill();run.dyn.stroke=_363.getStroke();if(_35c){var o={element:"column",index:j,run:run,shape:_363,x:j+0.5,y:v};this._connectEvents(o);_35e[j]=o;}if(this.animate){this._animateColumn(_363,dim.height-_358.b-_35b,h);}}}}this._eventSeries[run.name]=_35e;run.dirty=false;}this.dirty=false;return this;},_animateColumn:function(_364,_365,_366){fx.animateTransform(lang.delegate({shape:_364,duration:1200,transform:[{name:"translate",start:[0,_365-(_365/_366)],end:[0,0]},{name:"scale",start:[1,1/_366],end:[1,1]},{name:"original"}]},this.animate)).play();}});});},"dijit/place":function(){define("dijit/place",["dojo/_base/array","dojo/dom-geometry","dojo/dom-style","dojo/_base/kernel","dojo/_base/window","dojo/window","."],function(_367,_368,_369,_36a,win,_36b,_36c){function _36d(node,_36e,_36f,_370){var view=_36b.getBox();if(!node.parentNode||String(node.parentNode.tagName).toLowerCase()!="body"){win.body().appendChild(node);}var best=null;_367.some(_36e,function(_371){var _372=_371.corner;var pos=_371.pos;var _373=0;var _374={w:{"L":view.l+view.w-pos.x,"R":pos.x-view.l,"M":view.w}[_372.charAt(1)],h:{"T":view.t+view.h-pos.y,"B":pos.y-view.t,"M":view.h}[_372.charAt(0)]};if(_36f){var res=_36f(node,_371.aroundCorner,_372,_374,_370);_373=typeof res=="undefined"?0:res;}var _375=node.style;var _376=_375.display;var _377=_375.visibility;if(_375.display=="none"){_375.visibility="hidden";_375.display="";}var mb=_368.getMarginBox(node);_375.display=_376;_375.visibility=_377;var _378={"L":pos.x,"R":pos.x-mb.w,"M":Math.max(view.l,Math.min(view.l+view.w,pos.x+(mb.w>>1))-mb.w)}[_372.charAt(1)],_379={"T":pos.y,"B":pos.y-mb.h,"M":Math.max(view.t,Math.min(view.t+view.h,pos.y+(mb.h>>1))-mb.h)}[_372.charAt(0)],_37a=Math.max(view.l,_378),_37b=Math.max(view.t,_379),endX=Math.min(view.l+view.w,_378+mb.w),endY=Math.min(view.t+view.h,_379+mb.h),_37c=endX-_37a,_37d=endY-_37b;_373+=(mb.w-_37c)+(mb.h-_37d);if(best==null||_373<best.overflow){best={corner:_372,aroundCorner:_371.aroundCorner,x:_37a,y:_37b,w:_37c,h:_37d,overflow:_373,spaceAvailable:_374};}return !_373;});if(best.overflow&&_36f){_36f(node,best.aroundCorner,best.corner,best.spaceAvailable,_370);}var l=_368.isBodyLtr(),s=node.style;s.top=best.y+"px";s[l?"left":"right"]=(l?best.x:view.w-best.x-best.w)+"px";s[l?"right":"left"]="auto";return best;};return (_36c.place={at:function(node,pos,_37e,_37f){var _380=_367.map(_37e,function(_381){var c={corner:_381,pos:{x:pos.x,y:pos.y}};if(_37f){c.pos.x+=_381.charAt(1)=="L"?_37f.x:-_37f.x;c.pos.y+=_381.charAt(0)=="T"?_37f.y:-_37f.y;}return c;});return _36d(node,_380);},around:function(node,_382,_383,_384,_385){var _386=(typeof _382=="string"||"offsetWidth" in _382)?_368.position(_382,true):_382;if(_382.parentNode){var _387=_382.parentNode;while(_387&&_387.nodeType==1&&_387.nodeName!="BODY"){var _388=_368.position(_387,true);var _389=_369.getComputedStyle(_387).overflow;if(_389=="hidden"||_389=="auto"||_389=="scroll"){var _38a=Math.min(_386.y+_386.h,_388.y+_388.h);var _38b=Math.min(_386.x+_386.w,_388.x+_388.w);_386.x=Math.max(_386.x,_388.x);_386.y=Math.max(_386.y,_388.y);_386.h=_38a-_386.y;_386.w=_38b-_386.x;}_387=_387.parentNode;}}var x=_386.x,y=_386.y,_38c="w" in _386?_386.w:(_386.w=_386.width),_38d="h" in _386?_386.h:(_36a.deprecated("place.around: dijit.place.__Rectangle: { x:"+x+", y:"+y+", height:"+_386.height+", width:"+_38c+" } has been deprecated. Please use { x:"+x+", y:"+y+", h:"+_386.height+", w:"+_38c+" }","","2.0"),_386.h=_386.height);var _38e=[];function push(_38f,_390){_38e.push({aroundCorner:_38f,corner:_390,pos:{x:{"L":x,"R":x+_38c,"M":x+(_38c>>1)}[_38f.charAt(1)],y:{"T":y,"B":y+_38d,"M":y+(_38d>>1)}[_38f.charAt(0)]}});};_367.forEach(_383,function(pos){var ltr=_384;switch(pos){case "above-centered":push("TM","BM");break;case "below-centered":push("BM","TM");break;case "after-centered":ltr=!ltr;case "before-centered":push(ltr?"ML":"MR",ltr?"MR":"ML");break;case "after":ltr=!ltr;case "before":push(ltr?"TL":"TR",ltr?"TR":"TL");push(ltr?"BL":"BR",ltr?"BR":"BL");break;case "below-alt":ltr=!ltr;case "below":push(ltr?"BL":"BR",ltr?"TL":"TR");push(ltr?"BR":"BL",ltr?"TR":"TL");break;case "above-alt":ltr=!ltr;case "above":push(ltr?"TL":"TR",ltr?"BL":"BR");push(ltr?"TR":"TL",ltr?"BR":"BL");break;default:push(pos.aroundCorner,pos.corner);}});var _391=_36d(node,_38e,_385,{w:_38c,h:_38d});_391.aroundNodePos=_386;return _391;}});});},"dojox/lang/functional/array":function(){define("dojox/lang/functional/array",["dojo/_base/kernel","dojo/_base/lang","dojo/_base/array","dojo/_base/window","./lambda"],function(dojo,lang,arr,win,df){var _392={};lang.mixin(df,{filter:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var t=[],v,i,n;if(lang.isArray(a)){for(i=0,n=a.length;i<n;++i){v=a[i];if(f.call(o,v,i,a)){t.push(v);}}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){for(i=0;a.hasNext();){v=a.next();if(f.call(o,v,i++,a)){t.push(v);}}}else{for(i in a){if(!(i in _392)){v=a[i];if(f.call(o,v,i,a)){t.push(v);}}}}}return t;},forEach:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var i,n;if(lang.isArray(a)){for(i=0,n=a.length;i<n;f.call(o,a[i],i,a),++i){}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){for(i=0;a.hasNext();f.call(o,a.next(),i++,a)){}}else{for(i in a){if(!(i in _392)){f.call(o,a[i],i,a);}}}}return o;},map:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var t,n,i;if(lang.isArray(a)){t=new Array(n=a.length);for(i=0;i<n;t[i]=f.call(o,a[i],i,a),++i){}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){t=[];for(i=0;a.hasNext();t.push(f.call(o,a.next(),i++,a))){}}else{t=[];for(i in a){if(!(i in _392)){t.push(f.call(o,a[i],i,a));}}}}return t;},every:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var i,n;if(lang.isArray(a)){for(i=0,n=a.length;i<n;++i){if(!f.call(o,a[i],i,a)){return false;}}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){for(i=0;a.hasNext();){if(!f.call(o,a.next(),i++,a)){return false;}}}else{for(i in a){if(!(i in _392)){if(!f.call(o,a[i],i,a)){return false;}}}}}return true;},some:function(a,f,o){if(typeof a=="string"){a=a.split("");}o=o||win.global;f=df.lambda(f);var i,n;if(lang.isArray(a)){for(i=0,n=a.length;i<n;++i){if(f.call(o,a[i],i,a)){return true;}}}else{if(typeof a.hasNext=="function"&&typeof a.next=="function"){for(i=0;a.hasNext();){if(f.call(o,a.next(),i++,a)){return true;}}}else{for(i in a){if(!(i in _392)){if(f.call(o,a[i],i,a)){return true;}}}}}return false;}});return df;});},"dojox/charting/Theme":function(){define("dojox/charting/Theme",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","dojo/_base/Color","dojox/color/_base","dojox/color/Palette","dojox/lang/utils","dojox/gfx/gradutils"],function(lang,arr,_393,_394,_395,_396,dlu,dgg){var _397=_393("dojox.charting.Theme",null,{shapeSpaces:{shape:1,shapeX:1,shapeY:1},constructor:function(_398){_398=_398||{};var def=_397.defaultTheme;arr.forEach(["chart","plotarea","axis","series","marker","indicator"],function(name){this[name]=lang.delegate(def[name],_398[name]);},this);if(_398.seriesThemes&&_398.seriesThemes.length){this.colors=null;this.seriesThemes=_398.seriesThemes.slice(0);}else{this.seriesThemes=null;this.colors=(_398.colors||_397.defaultColors).slice(0);}this.markerThemes=null;if(_398.markerThemes&&_398.markerThemes.length){this.markerThemes=_398.markerThemes.slice(0);}this.markers=_398.markers?lang.clone(_398.markers):lang.delegate(_397.defaultMarkers);this.noGradConv=_398.noGradConv;this.noRadialConv=_398.noRadialConv;if(_398.reverseFills){this.reverseFills();}this._current=0;this._buildMarkerArray();},clone:function(){var _399=new _397({chart:this.chart,plotarea:this.plotarea,axis:this.axis,series:this.series,marker:this.marker,colors:this.colors,markers:this.markers,indicator:this.indicator,seriesThemes:this.seriesThemes,markerThemes:this.markerThemes,noGradConv:this.noGradConv,noRadialConv:this.noRadialConv});arr.forEach(["clone","clear","next","skip","addMixin","post","getTick"],function(name){if(this.hasOwnProperty(name)){_399[name]=this[name];}},this);return _399;},clear:function(){this._current=0;},next:function(_39a,_39b,_39c){var _39d=dlu.merge,_39e,_39f;if(this.colors){_39e=lang.delegate(this.series);_39f=lang.delegate(this.marker);var _3a0=new _394(this.colors[this._current%this.colors.length]),old;if(_39e.stroke&&_39e.stroke.color){_39e.stroke=lang.delegate(_39e.stroke);old=new _394(_39e.stroke.color);_39e.stroke.color=new _394(_3a0);_39e.stroke.color.a=old.a;}else{_39e.stroke={color:_3a0};}if(_39f.stroke&&_39f.stroke.color){_39f.stroke=lang.delegate(_39f.stroke);old=new _394(_39f.stroke.color);_39f.stroke.color=new _394(_3a0);_39f.stroke.color.a=old.a;}else{_39f.stroke={color:_3a0};}if(!_39e.fill||_39e.fill.type){_39e.fill=_3a0;}else{old=new _394(_39e.fill);_39e.fill=new _394(_3a0);_39e.fill.a=old.a;}if(!_39f.fill||_39f.fill.type){_39f.fill=_3a0;}else{old=new _394(_39f.fill);_39f.fill=new _394(_3a0);_39f.fill.a=old.a;}}else{_39e=this.seriesThemes?_39d(this.series,this.seriesThemes[this._current%this.seriesThemes.length]):this.series;_39f=this.markerThemes?_39d(this.marker,this.markerThemes[this._current%this.markerThemes.length]):_39e;}var _3a1=_39f&&_39f.symbol||this._markers[this._current%this._markers.length];var _3a2={series:_39e,marker:_39f,symbol:_3a1};++this._current;if(_39b){_3a2=this.addMixin(_3a2,_39a,_39b);}if(_39c){_3a2=this.post(_3a2,_39a);}return _3a2;},skip:function(){++this._current;},addMixin:function(_3a3,_3a4,_3a5,_3a6){if(lang.isArray(_3a5)){arr.forEach(_3a5,function(m){_3a3=this.addMixin(_3a3,_3a4,m);},this);}else{var t={};if("color" in _3a5){if(_3a4=="line"||_3a4=="area"){lang.setObject("series.stroke.color",_3a5.color,t);lang.setObject("marker.stroke.color",_3a5.color,t);}else{lang.setObject("series.fill",_3a5.color,t);}}arr.forEach(["stroke","outline","shadow","fill","font","fontColor","labelWiring"],function(name){var _3a7="marker"+name.charAt(0).toUpperCase()+name.substr(1),b=_3a7 in _3a5;if(name in _3a5){lang.setObject("series."+name,_3a5[name],t);if(!b){lang.setObject("marker."+name,_3a5[name],t);}}if(b){lang.setObject("marker."+name,_3a5[_3a7],t);}});if("marker" in _3a5){t.symbol=_3a5.marker;}_3a3=dlu.merge(_3a3,t);}if(_3a6){_3a3=this.post(_3a3,_3a4);}return _3a3;},post:function(_3a8,_3a9){var fill=_3a8.series.fill,t;if(!this.noGradConv&&this.shapeSpaces[fill.space]&&fill.type=="linear"){if(_3a9=="bar"){t={x1:fill.y1,y1:fill.x1,x2:fill.y2,y2:fill.x2};}else{if(!this.noRadialConv&&fill.space=="shape"&&(_3a9=="slice"||_3a9=="circle")){t={type:"radial",cx:0,cy:0,r:100};}}if(t){return dlu.merge(_3a8,{series:{fill:t}});}}return _3a8;},getTick:function(name,_3aa){var tick=this.axis.tick,_3ab=name+"Tick",_3ac=dlu.merge;if(tick){if(this.axis[_3ab]){tick=_3ac(tick,this.axis[_3ab]);}}else{tick=this.axis[_3ab];}if(_3aa){if(tick){if(_3aa[_3ab]){tick=_3ac(tick,_3aa[_3ab]);}}else{tick=_3aa[_3ab];}}return tick;},inspectObjects:function(f){arr.forEach(["chart","plotarea","axis","series","marker","indicator"],function(name){f(this[name]);},this);if(this.seriesThemes){arr.forEach(this.seriesThemes,f);}if(this.markerThemes){arr.forEach(this.markerThemes,f);}},reverseFills:function(){this.inspectObjects(function(o){if(o&&o.fill){o.fill=dgg.reverse(o.fill);}});},addMarker:function(name,_3ad){this.markers[name]=_3ad;this._buildMarkerArray();},setMarkers:function(obj){this.markers=obj;this._buildMarkerArray();},_buildMarkerArray:function(){this._markers=[];for(var p in this.markers){this._markers.push(this.markers[p]);}}});lang.mixin(_397,{defaultMarkers:{CIRCLE:"m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0",SQUARE:"m-3,-3 l0,6 6,0 0,-6 z",DIAMOND:"m0,-3 l3,3 -3,3 -3,-3 z",CROSS:"m0,-3 l0,6 m-3,-3 l6,0",X:"m-3,-3 l6,6 m0,-6 l-6,6",TRIANGLE:"m-3,3 l3,-6 3,6 z",TRIANGLE_INVERTED:"m-3,-3 l3,6 3,-6 z"},defaultColors:["#54544c","#858e94","#6e767a","#948585","#474747"],defaultTheme:{chart:{stroke:null,fill:"white",pageStyle:null,titleGap:20,titlePos:"top",titleFont:"normal normal bold 14pt Tahoma",titleFontColor:"#333"},plotarea:{stroke:null,fill:"white"},axis:{stroke:{color:"#333",width:1},tick:{color:"#666",position:"center",font:"normal normal normal 7pt Tahoma",fontColor:"#333",titleGap:15,titleFont:"normal normal normal 11pt Tahoma",titleFontColor:"#333",titleOrientation:"axis"},majorTick:{width:1,length:6},minorTick:{width:0.8,length:3},microTick:{width:0.5,length:1}},series:{stroke:{width:1.5,color:"#333"},outline:{width:0.1,color:"#ccc"},shadow:null,fill:"#ccc",font:"normal normal normal 8pt Tahoma",fontColor:"#000",labelWiring:{width:1,color:"#ccc"}},marker:{stroke:{width:1.5,color:"#333"},outline:{width:0.1,color:"#ccc"},shadow:null,fill:"#ccc",font:"normal normal normal 8pt Tahoma",fontColor:"#000"},indicator:{lineStroke:{width:1.5,color:"#333"},lineOutline:{width:0.1,color:"#ccc"},lineShadow:null,stroke:{width:1.5,color:"#333"},outline:{width:0.1,color:"#ccc"},shadow:null,fill:"#ccc",radius:3,font:"normal normal normal 10pt Tahoma",fontColor:"#000",markerFill:"#ccc",markerSymbol:"m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0",markerStroke:{width:1.5,color:"#333"},markerOutline:{width:0.1,color:"#ccc"},markerShadow:null}},defineColors:function(_3ae){_3ae=_3ae||{};var l,c=[],n=_3ae.num||5;if(_3ae.colors){l=_3ae.colors.length;for(var i=0;i<n;i++){c.push(_3ae.colors[i%l]);}return c;}if(_3ae.hue){var s=_3ae.saturation||100,st=_3ae.low||30,end=_3ae.high||90;l=(end+st)/2;return _395.Palette.generate(_395.fromHsv(_3ae.hue,s,l),"monochromatic").colors;}if(_3ae.generator){return _395.Palette.generate(_3ae.base,_3ae.generator).colors;}return c;},generateGradient:function(_3af,_3b0,_3b1){var fill=lang.delegate(_3af);fill.colors=[{offset:0,color:_3b0},{offset:1,color:_3b1}];return fill;},generateHslColor:function(_3b2,_3b3){_3b2=new _394(_3b2);var hsl=_3b2.toHsl(),_3b4=_395.fromHsl(hsl.h,hsl.s,_3b3);_3b4.a=_3b2.a;return _3b4;},generateHslGradient:function(_3b5,_3b6,_3b7,_3b8){_3b5=new _394(_3b5);var hsl=_3b5.toHsl(),_3b9=_395.fromHsl(hsl.h,hsl.s,_3b7),_3ba=_395.fromHsl(hsl.h,hsl.s,_3b8);_3b9.a=_3ba.a=_3b5.a;return _397.generateGradient(_3b6,_3b9,_3ba);}});return _397;});},"dojox/charting/themes/common":function(){define("dojox/charting/themes/common",["dojo/_base/lang"],function(lang){return lang.getObject("dojox.charting.themes",true);});},"dojox/charting/plot2d/common":function(){define("dojox/charting/plot2d/common",["dojo/_base/lang","dojo/_base/array","dojo/_base/Color","dojox/gfx","dojox/lang/functional","../scaler/common"],function(lang,arr,_3bb,g,df,sc){var _3bc=lang.getObject("dojox.charting.plot2d.common",true);return lang.mixin(_3bc,{doIfLoaded:sc.doIfLoaded,makeStroke:function(_3bd){if(!_3bd){return _3bd;}if(typeof _3bd=="string"||_3bd instanceof _3bb){_3bd={color:_3bd};}return g.makeParameters(g.defaultStroke,_3bd);},augmentColor:function(_3be,_3bf){var t=new _3bb(_3be),c=new _3bb(_3bf);c.a=t.a;return c;},augmentStroke:function(_3c0,_3c1){var s=_3bc.makeStroke(_3c0);if(s){s.color=_3bc.augmentColor(s.color,_3c1);}return s;},augmentFill:function(fill,_3c2){var fc,c=new _3bb(_3c2);if(typeof fill=="string"||fill instanceof _3bb){return _3bc.augmentColor(fill,_3c2);}return fill;},defaultStats:{vmin:Number.POSITIVE_INFINITY,vmax:Number.NEGATIVE_INFINITY,hmin:Number.POSITIVE_INFINITY,hmax:Number.NEGATIVE_INFINITY},collectSimpleStats:function(_3c3){var _3c4=lang.delegate(_3bc.defaultStats);for(var i=0;i<_3c3.length;++i){var run=_3c3[i];for(var j=0;j<run.data.length;j++){if(run.data[j]!==null){if(typeof run.data[j]=="number"){var _3c5=_3c4.vmin,_3c6=_3c4.vmax;if(!("ymin" in run)||!("ymax" in run)){arr.forEach(run.data,function(val,i){if(val!==null){var x=i+1,y=val;if(isNaN(y)){y=0;}_3c4.hmin=Math.min(_3c4.hmin,x);_3c4.hmax=Math.max(_3c4.hmax,x);_3c4.vmin=Math.min(_3c4.vmin,y);_3c4.vmax=Math.max(_3c4.vmax,y);}});}if("ymin" in run){_3c4.vmin=Math.min(_3c5,run.ymin);}if("ymax" in run){_3c4.vmax=Math.max(_3c6,run.ymax);}}else{var _3c7=_3c4.hmin,_3c8=_3c4.hmax,_3c5=_3c4.vmin,_3c6=_3c4.vmax;if(!("xmin" in run)||!("xmax" in run)||!("ymin" in run)||!("ymax" in run)){arr.forEach(run.data,function(val,i){if(val!==null){var x="x" in val?val.x:i+1,y=val.y;if(isNaN(x)){x=0;}if(isNaN(y)){y=0;}_3c4.hmin=Math.min(_3c4.hmin,x);_3c4.hmax=Math.max(_3c4.hmax,x);_3c4.vmin=Math.min(_3c4.vmin,y);_3c4.vmax=Math.max(_3c4.vmax,y);}});}if("xmin" in run){_3c4.hmin=Math.min(_3c7,run.xmin);}if("xmax" in run){_3c4.hmax=Math.max(_3c8,run.xmax);}if("ymin" in run){_3c4.vmin=Math.min(_3c5,run.ymin);}if("ymax" in run){_3c4.vmax=Math.max(_3c6,run.ymax);}}break;}}}return _3c4;},calculateBarSize:function(_3c9,opt,_3ca){if(!_3ca){_3ca=1;}var gap=opt.gap,size=(_3c9-2*gap)/_3ca;if("minBarSize" in opt){size=Math.max(size,opt.minBarSize);}if("maxBarSize" in opt){size=Math.min(size,opt.maxBarSize);}size=Math.max(size,1);gap=(_3c9-size*_3ca)/2;return {size:size,gap:gap};},collectStackedStats:function(_3cb){var _3cc=lang.clone(_3bc.defaultStats);if(_3cb.length){_3cc.hmin=Math.min(_3cc.hmin,1);_3cc.hmax=df.foldl(_3cb,"seed, run -> Math.max(seed, run.data.length)",_3cc.hmax);for(var i=0;i<_3cc.hmax;++i){var v=_3cb[0].data[i];v=v&&(typeof v=="number"?v:v.y);if(isNaN(v)){v=0;}_3cc.vmin=Math.min(_3cc.vmin,v);for(var j=1;j<_3cb.length;++j){var t=_3cb[j].data[i];t=t&&(typeof t=="number"?t:t.y);if(isNaN(t)){t=0;}v+=t;}_3cc.vmax=Math.max(_3cc.vmax,v);}}return _3cc;},curve:function(a,_3cd){var _3ce=a.slice(0);if(_3cd=="x"){_3ce[_3ce.length]=arr[0];}var p=arr.map(_3ce,function(item,i){if(i==0){return "M"+item.x+","+item.y;}if(!isNaN(_3cd)){var dx=item.x-_3ce[i-1].x,dy=_3ce[i-1].y;return "C"+(item.x-(_3cd-1)*(dx/_3cd))+","+dy+" "+(item.x-(dx/_3cd))+","+item.y+" "+item.x+","+item.y;}else{if(_3cd=="X"||_3cd=="x"||_3cd=="S"){var p0,p1=_3ce[i-1],p2=_3ce[i],p3;var bz1x,bz1y,bz2x,bz2y;var f=1/6;if(i==1){if(_3cd=="x"){p0=_3ce[_3ce.length-2];}else{p0=p1;}f=1/3;}else{p0=_3ce[i-2];}if(i==(_3ce.length-1)){if(_3cd=="x"){p3=_3ce[1];}else{p3=p2;}f=1/3;}else{p3=_3ce[i+1];}var p1p2=Math.sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));var p0p2=Math.sqrt((p2.x-p0.x)*(p2.x-p0.x)+(p2.y-p0.y)*(p2.y-p0.y));var p1p3=Math.sqrt((p3.x-p1.x)*(p3.x-p1.x)+(p3.y-p1.y)*(p3.y-p1.y));var _3cf=p0p2*f;var _3d0=p1p3*f;if(_3cf>p1p2/2&&_3d0>p1p2/2){_3cf=p1p2/2;_3d0=p1p2/2;}else{if(_3cf>p1p2/2){_3cf=p1p2/2;_3d0=p1p2/2*p1p3/p0p2;}else{if(_3d0>p1p2/2){_3d0=p1p2/2;_3cf=p1p2/2*p0p2/p1p3;}}}if(_3cd=="S"){if(p0==p1){_3cf=0;}if(p2==p3){_3d0=0;}}bz1x=p1.x+_3cf*(p2.x-p0.x)/p0p2;bz1y=p1.y+_3cf*(p2.y-p0.y)/p0p2;bz2x=p2.x-_3d0*(p3.x-p1.x)/p1p3;bz2y=p2.y-_3d0*(p3.y-p1.y)/p1p3;}}return "C"+(bz1x+","+bz1y+" "+bz2x+","+bz2y+" "+p2.x+","+p2.y);});return p.join(" ");},getLabel:function(_3d1,_3d2,_3d3){return sc.doIfLoaded("dojo/number",function(_3d4){return (_3d2?_3d4.format(_3d1,{places:_3d3}):_3d4.format(_3d1))||"";},function(){return _3d2?_3d1.toFixed(_3d3):_3d1.toString();});}});});},"dijit/_Widget":function(){define("dijit/_Widget",["dojo/aspect","dojo/_base/config","dojo/_base/connect","dojo/_base/declare","dojo/_base/kernel","dojo/_base/lang","dojo/query","dojo/ready","./registry","./_WidgetBase","./_OnDijitClickMixin","./_FocusMixin","dojo/uacss","./hccss"],function(_3d5,_3d6,_3d7,_3d8,_3d9,lang,_3da,_3db,_3dc,_3dd,_3de,_3df){function _3e0(){};function _3e1(_3e2){return function(obj,_3e3,_3e4,_3e5){if(obj&&typeof _3e3=="string"&&obj[_3e3]==_3e0){return obj.on(_3e3.substring(2).toLowerCase(),lang.hitch(_3e4,_3e5));}return _3e2.apply(_3d7,arguments);};};_3d5.around(_3d7,"connect",_3e1);if(_3d9.connect){_3d5.around(_3d9,"connect",_3e1);}var _3e6=_3d8("dijit._Widget",[_3dd,_3de,_3df],{onClick:_3e0,onDblClick:_3e0,onKeyDown:_3e0,onKeyPress:_3e0,onKeyUp:_3e0,onMouseDown:_3e0,onMouseMove:_3e0,onMouseOut:_3e0,onMouseOver:_3e0,onMouseLeave:_3e0,onMouseEnter:_3e0,onMouseUp:_3e0,constructor:function(_3e7){this._toConnect={};for(var name in _3e7){if(this[name]===_3e0){this._toConnect[name.replace(/^on/,"").toLowerCase()]=_3e7[name];delete _3e7[name];}}},postCreate:function(){this.inherited(arguments);for(var name in this._toConnect){this.on(name,this._toConnect[name]);}delete this._toConnect;},on:function(type,func){if(this[this._onMap(type)]===_3e0){return _3d7.connect(this.domNode,type.toLowerCase(),this,func);}return this.inherited(arguments);},_setFocusedAttr:function(val){this._focused=val;this._set("focused",val);},setAttribute:function(attr,_3e8){_3d9.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.","","2.0");this.set(attr,_3e8);},attr:function(name,_3e9){if(_3d6.isDebug){var _3ea=arguments.callee._ach||(arguments.callee._ach={}),_3eb=(arguments.callee.caller||"unknown caller").toString();if(!_3ea[_3eb]){_3d9.deprecated(this.declaredClass+"::attr() is deprecated. Use get() or set() instead, called from "+_3eb,"","2.0");_3ea[_3eb]=true;}}var args=arguments.length;if(args>=2||typeof name==="object"){return this.set.apply(this,arguments);}else{return this.get(name);}},getDescendants:function(){_3d9.deprecated(this.declaredClass+"::getDescendants() is deprecated. Use getChildren() instead.","","2.0");return this.containerNode?_3da("[widgetId]",this.containerNode).map(_3dc.byNode):[];},_onShow:function(){this.onShow();},onShow:function(){},onHide:function(){},onClose:function(){return true;}});if(!_3d9.isAsync){_3db(0,function(){var _3ec=["dijit/_base"];require(_3ec);});}return _3e6;});},"dijit/_FocusMixin":function(){define("dijit/_FocusMixin",["./focus","./_WidgetBase","dojo/_base/declare","dojo/_base/lang"],function(_3ed,_3ee,_3ef,lang){lang.extend(_3ee,{focused:false,onFocus:function(){},onBlur:function(){},_onFocus:function(){this.onFocus();},_onBlur:function(){this.onBlur();}});return _3ef("dijit._FocusMixin",null,{_focusManager:_3ed});});},"dijit/_OnDijitClickMixin":function(){define("dijit/_OnDijitClickMixin",["dojo/on","dojo/_base/array","dojo/keys","dojo/_base/declare","dojo/_base/sniff","dojo/_base/unload","dojo/_base/window"],function(on,_3f0,keys,_3f1,has,_3f2,win){var _3f3=null;if(has("ie")){(function(){var _3f4=function(evt){_3f3=evt.srcElement;};win.doc.attachEvent("onkeydown",_3f4);_3f2.addOnWindowUnload(function(){win.doc.detachEvent("onkeydown",_3f4);});})();}else{win.doc.addEventListener("keydown",function(evt){_3f3=evt.target;},true);}var _3f5=function(node,_3f6){if(/input|button/i.test(node.nodeName)){return on(node,"click",_3f6);}else{function _3f7(e){return (e.keyCode==keys.ENTER||e.keyCode==keys.SPACE)&&!e.ctrlKey&&!e.shiftKey&&!e.altKey&&!e.metaKey;};var _3f8=[on(node,"keypress",function(e){if(_3f7(e)){_3f3=e.target;e.preventDefault();}}),on(node,"keyup",function(e){if(_3f7(e)&&e.target==_3f3){_3f3=null;_3f6.call(this,e);}}),on(node,"click",function(e){_3f6.call(this,e);})];return {remove:function(){_3f0.forEach(_3f8,function(h){h.remove();});}};}};return _3f1("dijit._OnDijitClickMixin",null,{connect:function(obj,_3f9,_3fa){return this.inherited(arguments,[obj,_3f9=="ondijitclick"?_3f5:_3f9,_3fa]);}});});},"dojo/cache":function(){define(["./_base/kernel","./text"],function(dojo,text){return dojo.cache;});},"dojox/charting/plot2d/Bars":function(){define("dojox/charting/plot2d/Bars",["dojo/_base/kernel","dojo/_base/lang","dojo/_base/array","dojo/_base/declare","./Base","./common","dojox/gfx/fx","dojox/lang/utils","dojox/lang/functional","dojox/lang/functional/reversed"],function(dojo,lang,arr,_3fb,Base,dc,fx,du,df,dfr){var _3fc=dfr.lambda("item.purgeGroup()");return _3fb("dojox.charting.plot2d.Bars",Base,{defaultParams:{hAxis:"x",vAxis:"y",gap:0,animate:null,enableCache:false},optionalParams:{minBarSize:1,maxBarSize:1,stroke:{},outline:{},shadow:{},fill:{},font:"",fontColor:""},constructor:function(_3fd,_3fe){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_3fe);du.updateWithPattern(this.opt,_3fe,this.optionalParams);this.series=[];this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.animate=this.opt.animate;},getSeriesStats:function(){var _3ff=dc.collectSimpleStats(this.series),t;_3ff.hmin-=0.5;_3ff.hmax+=0.5;t=_3ff.hmin,_3ff.hmin=_3ff.vmin,_3ff.vmin=t;t=_3ff.hmax,_3ff.hmax=_3ff.vmax,_3ff.vmax=t;return _3ff;},createRect:function(run,_400,_401){var rect;if(this.opt.enableCache&&run._rectFreePool.length>0){rect=run._rectFreePool.pop();rect.setShape(_401);_400.add(rect);}else{rect=_400.createRect(_401);}if(this.opt.enableCache){run._rectUsePool.push(rect);}return rect;},render:function(dim,_402){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_402);}this.dirty=this.isDirty();this.resetEvents();if(this.dirty){arr.forEach(this.series,_3fc);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,f,gap,_403,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_404=Math.max(0,this._hScaler.bounds.lower),_405=ht(_404),_406=this.events();f=dc.calculateBarSize(this._vScaler.bounds.scale,this.opt);gap=f.gap;_403=f.size;for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();if(this.opt.enableCache){run._rectFreePool=(run._rectFreePool?run._rectFreePool:[]).concat(run._rectUsePool?run._rectUsePool:[]);run._rectUsePool=[];}var _407=t.next("bar",[this.opt,run]),s=run.group,_408=new Array(run.data.length);for(var j=0;j<run.data.length;++j){var _409=run.data[j];if(_409!==null){var v=typeof _409=="number"?_409:_409.y,hv=ht(v),_40a=hv-_405,w=Math.abs(_40a),_40b=typeof _409!="number"?t.addMixin(_407,"bar",_409,true):t.post(_407,"bar");if(w>=0&&_403>=1){var rect={x:_402.l+(v<_404?hv:_405),y:dim.height-_402.b-vt(j+1.5)+gap,width:w,height:_403};var _40c=this._plotFill(_40b.series.fill,dim,_402);_40c=this._shapeFill(_40c,rect);var _40d=this.createRect(run,s,rect).setFill(_40c).setStroke(_40b.series.stroke);run.dyn.fill=_40d.getFill();run.dyn.stroke=_40d.getStroke();if(_406){var o={element:"bar",index:j,run:run,shape:_40d,x:v,y:j+1.5};this._connectEvents(o);_408[j]=o;}if(this.animate){this._animateBar(_40d,_402.l+_405,-w);}}}}this._eventSeries[run.name]=_408;run.dirty=false;}this.dirty=false;return this;},_animateBar:function(_40e,_40f,_410){fx.animateTransform(lang.delegate({shape:_40e,duration:1200,transform:[{name:"translate",start:[_40f-(_40f/_410),0],end:[0,0]},{name:"scale",start:[1/_410,1],end:[1,1]},{name:"original"}]},this.animate)).play();}});});},"dojox/gfx/_base":function(){define("dojox/gfx/_base",["dojo/_base/lang","dojo/_base/html","dojo/_base/Color","dojo/_base/sniff","dojo/_base/window","dojo/_base/array","dojo/dom","dojo/dom-construct","dojo/dom-geometry"],function(lang,html,_411,has,win,arr,dom,_412,_413){var g=lang.getObject("dojox.gfx",true),b=g._base={};g._hasClass=function(node,_414){var cls=node.getAttribute("className");return cls&&(" "+cls+" ").indexOf(" "+_414+" ")>=0;};g._addClass=function(node,_415){var cls=node.getAttribute("className")||"";if(!cls||(" "+cls+" ").indexOf(" "+_415+" ")<0){node.setAttribute("className",cls+(cls?" ":"")+_415);}};g._removeClass=function(node,_416){var cls=node.getAttribute("className");if(cls){node.setAttribute("className",cls.replace(new RegExp("(^|\\s+)"+_416+"(\\s+|$)"),"$1$2"));}};b._getFontMeasurements=function(){var _417={"1em":0,"1ex":0,"100%":0,"12pt":0,"16px":0,"xx-small":0,"x-small":0,"small":0,"medium":0,"large":0,"x-large":0,"xx-large":0};var p;if(has("ie")){win.doc.documentElement.style.fontSize="100%";}var div=_412.create("div",{style:{position:"absolute",left:"0",top:"-100px",width:"30px",height:"1000em",borderWidth:"0",margin:"0",padding:"0",outline:"none",lineHeight:"1",overflow:"hidden"}},win.body());for(p in _417){div.style.fontSize=p;_417[p]=Math.round(div.offsetHeight*12/16)*16/12/1000;}win.body().removeChild(div);return _417;};var _418=null;b._getCachedFontMeasurements=function(_419){if(_419||!_418){_418=b._getFontMeasurements();}return _418;};var _41a=null,_41b={};b._getTextBox=function(text,_41c,_41d){var m,s,al=arguments.length;var i;if(!_41a){_41a=_412.create("div",{style:{position:"absolute",top:"-10000px",left:"0"}},win.body());}m=_41a;m.className="";s=m.style;s.borderWidth="0";s.margin="0";s.padding="0";s.outline="0";if(al>1&&_41c){for(i in _41c){if(i in _41b){continue;}s[i]=_41c[i];}}if(al>2&&_41d){m.className=_41d;}m.innerHTML=text;if(m["getBoundingClientRect"]){var bcr=m.getBoundingClientRect();return {l:bcr.left,t:bcr.top,w:bcr.width||(bcr.right-bcr.left),h:bcr.height||(bcr.bottom-bcr.top)};}else{return _413.getMarginBox(m);}};var _41e=0;b._getUniqueId=function(){var id;do{id=dojo._scopeName+"xUnique"+(++_41e);}while(dom.byId(id));return id;};lang.mixin(g,{defaultPath:{type:"path",path:""},defaultPolyline:{type:"polyline",points:[]},defaultRect:{type:"rect",x:0,y:0,width:100,height:100,r:0},defaultEllipse:{type:"ellipse",cx:0,cy:0,rx:200,ry:100},defaultCircle:{type:"circle",cx:0,cy:0,r:100},defaultLine:{type:"line",x1:0,y1:0,x2:100,y2:100},defaultImage:{type:"image",x:0,y:0,width:0,height:0,src:""},defaultText:{type:"text",x:0,y:0,text:"",align:"start",decoration:"none",rotated:false,kerning:true},defaultTextPath:{type:"textpath",text:"",align:"start",decoration:"none",rotated:false,kerning:true},defaultStroke:{type:"stroke",color:"black",style:"solid",width:1,cap:"butt",join:4},defaultLinearGradient:{type:"linear",x1:0,y1:0,x2:100,y2:100,colors:[{offset:0,color:"black"},{offset:1,color:"white"}]},defaultRadialGradient:{type:"radial",cx:0,cy:0,r:100,colors:[{offset:0,color:"black"},{offset:1,color:"white"}]},defaultPattern:{type:"pattern",x:0,y:0,width:0,height:0,src:""},defaultFont:{type:"font",style:"normal",variant:"normal",weight:"normal",size:"10pt",family:"serif"},getDefault:(function(){var _41f={};return function(type){var t=_41f[type];if(t){return new t();}t=_41f[type]=new Function();t.prototype=g["default"+type];return new t();};})(),normalizeColor:function(_420){return (_420 instanceof _411)?_420:new _411(_420);},normalizeParameters:function(_421,_422){var x;if(_422){var _423={};for(x in _421){if(x in _422&&!(x in _423)){_421[x]=_422[x];}}}return _421;},makeParameters:function(_424,_425){var i=null;if(!_425){return lang.delegate(_424);}var _426={};for(i in _424){if(!(i in _426)){_426[i]=lang.clone((i in _425)?_425[i]:_424[i]);}}return _426;},formatNumber:function(x,_427){var val=x.toString();if(val.indexOf("e")>=0){val=x.toFixed(4);}else{var _428=val.indexOf(".");if(_428>=0&&val.length-_428>5){val=x.toFixed(4);}}if(x<0){return val;}return _427?" "+val:val;},makeFontString:function(font){return font.style+" "+font.variant+" "+font.weight+" "+font.size+" "+font.family;},splitFontString:function(str){var font=g.getDefault("Font");var t=str.split(/\s+/);do{if(t.length<5){break;}font.style=t[0];font.variant=t[1];font.weight=t[2];var i=t[3].indexOf("/");font.size=i<0?t[3]:t[3].substring(0,i);var j=4;if(i<0){if(t[4]=="/"){j=6;}else{if(t[4].charAt(0)=="/"){j=5;}}}if(j<t.length){font.family=t.slice(j).join(" ");}}while(false);return font;},cm_in_pt:72/2.54,mm_in_pt:7.2/2.54,px_in_pt:function(){return g._base._getCachedFontMeasurements()["12pt"]/12;},pt2px:function(len){return len*g.px_in_pt();},px2pt:function(len){return len/g.px_in_pt();},normalizedLength:function(len){if(len.length===0){return 0;}if(len.length>2){var _429=g.px_in_pt();var val=parseFloat(len);switch(len.slice(-2)){case "px":return val;case "pt":return val*_429;case "in":return val*72*_429;case "pc":return val*12*_429;case "mm":return val*g.mm_in_pt*_429;case "cm":return val*g.cm_in_pt*_429;}}return parseFloat(len);},pathVmlRegExp:/([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,pathSvgRegExp:/([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,equalSources:function(a,b){return a&&b&&a===b;},switchTo:function(_42a){var ns=typeof _42a=="string"?g[_42a]:_42a;if(ns){arr.forEach(["Group","Rect","Ellipse","Circle","Line","Polyline","Image","Text","Path","TextPath","Surface","createSurface","fixTarget"],function(name){g[name]=ns[name];});}}});return g;});},"dijit/focus":function(){define("dijit/focus",["dojo/aspect","dojo/_base/declare","dojo/dom","dojo/dom-attr","dojo/dom-construct","dojo/Evented","dojo/_base/lang","dojo/on","dojo/ready","dojo/_base/sniff","dojo/Stateful","dojo/_base/unload","dojo/_base/window","dojo/window","./a11y","./registry","."],function(_42b,_42c,dom,_42d,_42e,_42f,lang,on,_430,has,_431,_432,win,_433,a11y,_434,_435){var _436=_42c([_431,_42f],{curNode:null,activeStack:[],constructor:function(){var _437=lang.hitch(this,function(node){if(dom.isDescendant(this.curNode,node)){this.set("curNode",null);}if(dom.isDescendant(this.prevNode,node)){this.set("prevNode",null);}});_42b.before(_42e,"empty",_437);_42b.before(_42e,"destroy",_437);},registerIframe:function(_438){return this.registerWin(_438.contentWindow,_438);},registerWin:function(_439,_43a){var _43b=this;var _43c=function(evt){_43b._justMouseDowned=true;setTimeout(function(){_43b._justMouseDowned=false;},0);if(has("ie")&&evt&&evt.srcElement&&evt.srcElement.parentNode==null){return;}_43b._onTouchNode(_43a||evt.target||evt.srcElement,"mouse");};var doc=has("ie")?_439.document.documentElement:_439.document;if(doc){if(has("ie")){_439.document.body.attachEvent("onmousedown",_43c);var _43d=function(evt){var tag=evt.srcElement.tagName.toLowerCase();if(tag=="#document"||tag=="body"){return;}if(a11y.isTabNavigable(evt.srcElement)){_43b._onFocusNode(_43a||evt.srcElement);}else{_43b._onTouchNode(_43a||evt.srcElement);}};doc.attachEvent("onactivate",_43d);var _43e=function(evt){_43b._onBlurNode(_43a||evt.srcElement);};doc.attachEvent("ondeactivate",_43e);return {remove:function(){_439.document.detachEvent("onmousedown",_43c);doc.detachEvent("onactivate",_43d);doc.detachEvent("ondeactivate",_43e);doc=null;}};}else{doc.body.addEventListener("mousedown",_43c,true);doc.body.addEventListener("touchstart",_43c,true);var _43f=function(evt){_43b._onFocusNode(_43a||evt.target);};doc.addEventListener("focus",_43f,true);var _440=function(evt){_43b._onBlurNode(_43a||evt.target);};doc.addEventListener("blur",_440,true);return {remove:function(){doc.body.removeEventListener("mousedown",_43c,true);doc.body.removeEventListener("touchstart",_43c,true);doc.removeEventListener("focus",_43f,true);doc.removeEventListener("blur",_440,true);doc=null;}};}}},_onBlurNode:function(){this.set("prevNode",this.curNode);this.set("curNode",null);if(this._justMouseDowned){return;}if(this._clearActiveWidgetsTimer){clearTimeout(this._clearActiveWidgetsTimer);}this._clearActiveWidgetsTimer=setTimeout(lang.hitch(this,function(){delete this._clearActiveWidgetsTimer;this._setStack([]);this.prevNode=null;}),100);},_onTouchNode:function(node,by){if(this._clearActiveWidgetsTimer){clearTimeout(this._clearActiveWidgetsTimer);delete this._clearActiveWidgetsTimer;}var _441=[];try{while(node){var _442=_42d.get(node,"dijitPopupParent");if(_442){node=_434.byId(_442).domNode;}else{if(node.tagName&&node.tagName.toLowerCase()=="body"){if(node===win.body()){break;}node=_433.get(node.ownerDocument).frameElement;}else{var id=node.getAttribute&&node.getAttribute("widgetId"),_443=id&&_434.byId(id);if(_443&&!(by=="mouse"&&_443.get("disabled"))){_441.unshift(id);}node=node.parentNode;}}}}catch(e){}this._setStack(_441,by);},_onFocusNode:function(node){if(!node){return;}if(node.nodeType==9){return;}this._onTouchNode(node);if(node==this.curNode){return;}this.set("curNode",node);},_setStack:function(_444,by){var _445=this.activeStack;this.set("activeStack",_444);for(var _446=0;_446<Math.min(_445.length,_444.length);_446++){if(_445[_446]!=_444[_446]){break;}}var _447;for(var i=_445.length-1;i>=_446;i--){_447=_434.byId(_445[i]);if(_447){_447._hasBeenBlurred=true;_447.set("focused",false);if(_447._focusManager==this){_447._onBlur(by);}this.emit("widget-blur",_447,by);}}for(i=_446;i<_444.length;i++){_447=_434.byId(_444[i]);if(_447){_447.set("focused",true);if(_447._focusManager==this){_447._onFocus(by);}this.emit("widget-focus",_447,by);}}},focus:function(node){if(node){try{node.focus();}catch(e){}}}});var _448=new _436();_430(function(){var _449=_448.registerWin(win.doc.parentWindow||win.doc.defaultView);if(has("ie")){_432.addOnWindowUnload(function(){_449.remove();_449=null;});}});_435.focus=function(node){_448.focus(node);};for(var attr in _448){if(!/^_/.test(attr)){_435.focus[attr]=typeof _448[attr]=="function"?lang.hitch(_448,attr):_448[attr];}}_448.watch(function(attr,_44a,_44b){_435.focus[attr]=_44b;});return _448;});},"dojox/charting/widget/Legend":function(){define("dojox/charting/widget/Legend",["dojo/_base/lang","dojo/_base/html","dojo/_base/declare","dijit/_Widget","dojox/gfx","dojo/_base/array","dojox/lang/functional","dojox/lang/functional/array","dojox/lang/functional/fold","dojo/dom","dojo/dom-construct","dojo/dom-class","dijit/_base/manager"],function(lang,html,_44c,_44d,gfx,_44e,df,dfa,dff,dom,_44f,_450,_451){var _452=/\.(StackedColumns|StackedAreas|ClusteredBars)$/;return _44c("dojox.charting.widget.Legend",_44d,{chartRef:"",horizontal:true,swatchSize:18,legendBody:null,postCreate:function(){if(!this.chart){if(!this.chartRef){return;}this.chart=_451.byId(this.chartRef);if(!this.chart){var node=dom.byId(this.chartRef);if(node){this.chart=_451.byNode(node);}else{return;}}this.series=this.chart.chart.series;}else{this.series=this.chart.series;}this.refresh();},buildRendering:function(){this.domNode=_44f.create("table",{role:"group","aria-label":"chart legend","class":"dojoxLegendNode"});this.legendBody=_44f.create("tbody",null,this.domNode);this.inherited(arguments);},refresh:function(){if(this._surfaces){_44e.forEach(this._surfaces,function(_453){_453.destroy();});}this._surfaces=[];while(this.legendBody.lastChild){_44f.destroy(this.legendBody.lastChild);}if(this.horizontal){_450.add(this.domNode,"dojoxLegendHorizontal");this._tr=_44f.create("tr",null,this.legendBody);this._inrow=0;}var s=this.series;if(s.length==0){return;}if(s[0].chart.stack[0].declaredClass=="dojox.charting.plot2d.Pie"){var t=s[0].chart.stack[0];if(typeof t.run.data[0]=="number"){var _454=df.map(t.run.data,"Math.max(x, 0)");if(df.every(_454,"<= 0")){return;}var _455=df.map(_454,"/this",df.foldl(_454,"+",0));_44e.forEach(_455,function(x,i){this._addLabel(t.dyn[i],t._getLabel(x*100)+"%");},this);}else{_44e.forEach(t.run.data,function(x,i){this._addLabel(t.dyn[i],x.legend||x.text||x.y);},this);}}else{if(this._isReversal()){s=s.slice(0).reverse();}_44e.forEach(s,function(x){this._addLabel(x.dyn,x.legend||x.name);},this);}},_addLabel:function(dyn,_456){var _457=_44f.create("td"),icon=_44f.create("div",null,_457),text=_44f.create("label",null,_457),div=_44f.create("div",{style:{"width":this.swatchSize+"px","height":this.swatchSize+"px","float":"left"}},icon);_450.add(icon,"dojoxLegendIcon dijitInline");_450.add(text,"dojoxLegendText");if(this._tr){this._tr.appendChild(_457);if(++this._inrow===this.horizontal){this._tr=_44f.create("tr",null,this.legendBody);this._inrow=0;}}else{var tr=_44f.create("tr",null,this.legendBody);tr.appendChild(_457);}this._makeIcon(div,dyn);text.innerHTML=String(_456);text.dir=this.getTextDir(_456,text.dir);},_makeIcon:function(div,dyn){var mb={h:this.swatchSize,w:this.swatchSize};var _458=gfx.createSurface(div,mb.w,mb.h);this._surfaces.push(_458);if(dyn.fill){_458.createRect({x:2,y:2,width:mb.w-4,height:mb.h-4}).setFill(dyn.fill).setStroke(dyn.stroke);}else{if(dyn.stroke||dyn.marker){var line={x1:0,y1:mb.h/2,x2:mb.w,y2:mb.h/2};if(dyn.stroke){_458.createLine(line).setStroke(dyn.stroke);}if(dyn.marker){var c={x:mb.w/2,y:mb.h/2};if(dyn.stroke){_458.createPath({path:"M"+c.x+" "+c.y+" "+dyn.marker}).setFill(dyn.stroke.color).setStroke(dyn.stroke);}else{_458.createPath({path:"M"+c.x+" "+c.y+" "+dyn.marker}).setFill(dyn.color).setStroke(dyn.color);}}}else{_458.createRect({x:2,y:2,width:mb.w-4,height:mb.h-4}).setStroke("black");_458.createLine({x1:2,y1:2,x2:mb.w-2,y2:mb.h-2}).setStroke("black");_458.createLine({x1:2,y1:mb.h-2,x2:mb.w-2,y2:2}).setStroke("black");}}},_isReversal:function(){return (!this.horizontal)&&_44e.some(this.chart.stack,function(item){return _452.test(item.declaredClass);});}});});},"dojox/charting/plot2d/StackedLines":function(){define("dojox/charting/plot2d/StackedLines",["dojo/_base/declare","./Stacked"],function(_459,_45a){return _459("dojox.charting.plot2d.StackedLines",_45a,{constructor:function(){this.opt.lines=true;}});});},"dojox/charting/plot2d/StackedColumns":function(){define("dojox/charting/plot2d/StackedColumns",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","./Columns","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/functional/sequence"],function(lang,arr,_45b,_45c,dc,df,dfr,dfs){var _45d=dfr.lambda("item.purgeGroup()");return _45b("dojox.charting.plot2d.StackedColumns",_45c,{getSeriesStats:function(){var _45e=dc.collectStackedStats(this.series);this._maxRunLength=_45e.hmax;_45e.hmin-=0.5;_45e.hmax+=0.5;return _45e;},render:function(dim,_45f){if(this._maxRunLength<=0){return this;}var acc=df.repeat(this._maxRunLength,"-> 0",0);for(var i=0;i<this.series.length;++i){var run=this.series[i];for(var j=0;j<run.data.length;++j){var _460=run.data[j];if(_460!==null){var v=typeof _460=="number"?_460:_460.y;if(isNaN(v)){v=0;}acc[j]+=v;}}}if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_45f);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_45d);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,f,gap,_461,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_462=this.events();f=dc.calculateBarSize(this._hScaler.bounds.scale,this.opt);gap=f.gap;_461=f.size;for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();var _463=t.next("column",[this.opt,run]),s=run.group,_464=new Array(acc.length);for(var j=0;j<acc.length;++j){var _460=run.data[j];if(_460!==null){var v=acc[j],_465=vt(v),_466=typeof _460!="number"?t.addMixin(_463,"column",_460,true):t.post(_463,"column");if(_461>=1&&_465>=0){var rect={x:_45f.l+ht(j+0.5)+gap,y:dim.height-_45f.b-vt(v),width:_461,height:_465};var _467=this._plotFill(_466.series.fill,dim,_45f);_467=this._shapeFill(_467,rect);var _468=s.createRect(rect).setFill(_467).setStroke(_466.series.stroke);run.dyn.fill=_468.getFill();run.dyn.stroke=_468.getStroke();if(_462){var o={element:"column",index:j,run:run,shape:_468,x:j+0.5,y:v};this._connectEvents(o);_464[j]=o;}if(this.animate){this._animateColumn(_468,dim.height-_45f.b,_465);}}}}this._eventSeries[run.name]=_464;run.dirty=false;for(var j=0;j<run.data.length;++j){var _460=run.data[j];if(_460!==null){var v=typeof _460=="number"?_460:_460.y;if(isNaN(v)){v=0;}acc[j]-=v;}}}this.dirty=false;return this;}});});},"dojox/charting/Series":function(){define(["dojo/_base/lang","dojo/_base/declare","./Element"],function(lang,_469,_46a){return _469("dojox.charting.Series",_46a,{constructor:function(_46b,data,_46c){lang.mixin(this,_46c);if(typeof this.plot!="string"){this.plot="default";}this.update(data);},clear:function(){this.dyn={};},update:function(data){if(lang.isArray(data)){this.data=data;}else{this.source=data;this.data=this.source.data;if(this.source.setSeriesObject){this.source.setSeriesObject(this);}}this.dirty=true;this.clear();}});});},"dojox/charting/plot2d/Default":function(){define("dojox/charting/plot2d/Default",["dojo/_base/lang","dojo/_base/declare","dojo/_base/array","./Base","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils","dojox/gfx/fx"],function(lang,_46d,arr,Base,dc,df,dfr,du,fx){var _46e=dfr.lambda("item.purgeGroup()");var _46f=1200;return _46d("dojox.charting.plot2d.Default",Base,{defaultParams:{hAxis:"x",vAxis:"y",lines:true,areas:false,markers:false,tension:"",animate:false,enableCache:false},optionalParams:{stroke:{},outline:{},shadow:{},fill:{},font:"",fontColor:"",markerStroke:{},markerOutline:{},markerShadow:{},markerFill:{},markerFont:"",markerFontColor:""},constructor:function(_470,_471){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_471);du.updateWithPattern(this.opt,_471,this.optionalParams);this.series=[];this.hAxis=this.opt.hAxis;this.vAxis=this.opt.vAxis;this.animate=this.opt.animate;},createPath:function(run,_472,_473){var path;if(this.opt.enableCache&&run._pathFreePool.length>0){path=run._pathFreePool.pop();path.setShape(_473);_472.add(path);}else{path=_472.createPath(_473);}if(this.opt.enableCache){run._pathUsePool.push(path);}return path;},render:function(dim,_474){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_474);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_46e);this._eventSeries={};this.cleanGroup();this.group.setTransform(null);var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,_475,_476,_477,_478=this.events();for(var i=this.series.length-1;i>=0;--i){var run=this.series[i];if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();if(this.opt.enableCache){run._pathFreePool=(run._pathFreePool?run._pathFreePool:[]).concat(run._pathUsePool?run._pathUsePool:[]);run._pathUsePool=[];}if(!run.data.length){run.dirty=false;t.skip();continue;}var _479=t.next(this.opt.areas?"area":"line",[this.opt,run],true),s=run.group,_47a=[],_47b=[],rseg=null,_47c,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_47d=this._eventSeries[run.name]=new Array(run.data.length);var _47e=typeof run.data[0]=="number";var min=_47e?Math.max(0,Math.floor(this._hScaler.bounds.from-1)):0,max=_47e?Math.min(run.data.length,Math.ceil(this._hScaler.bounds.to)):run.data.length;for(var j=min;j<max;j++){if(run.data[j]!=null){if(!rseg){rseg=[];_47b.push(j);_47a.push(rseg);}rseg.push(run.data[j]);}else{rseg=null;}}for(var seg=0;seg<_47a.length;seg++){if(typeof _47a[seg][0]=="number"){_47c=arr.map(_47a[seg],function(v,i){return {x:ht(i+_47b[seg]+1)+_474.l,y:dim.height-_474.b-vt(v)};},this);}else{_47c=arr.map(_47a[seg],function(v,i){return {x:ht(v.x)+_474.l,y:dim.height-_474.b-vt(v.y)};},this);}var _47f=this.opt.tension?dc.curve(_47c,this.opt.tension):"";if(this.opt.areas&&_47c.length>1){var fill=_479.series.fill;var _480=lang.clone(_47c);if(this.opt.tension){var _481="L"+_480[_480.length-1].x+","+(dim.height-_474.b)+" L"+_480[0].x+","+(dim.height-_474.b)+" L"+_480[0].x+","+_480[0].y;run.dyn.fill=s.createPath(_47f+" "+_481).setFill(fill).getFill();}else{_480.push({x:_47c[_47c.length-1].x,y:dim.height-_474.b});_480.push({x:_47c[0].x,y:dim.height-_474.b});_480.push(_47c[0]);run.dyn.fill=s.createPolyline(_480).setFill(fill).getFill();}}if(this.opt.lines||this.opt.markers){_475=_479.series.stroke;if(_479.series.outline){_476=run.dyn.outline=dc.makeStroke(_479.series.outline);_476.width=2*_476.width+_475.width;}}if(this.opt.markers){run.dyn.marker=_479.symbol;}var _482=null,_483=null,_484=null;if(_475&&_479.series.shadow&&_47c.length>1){var _485=_479.series.shadow,_486=arr.map(_47c,function(c){return {x:c.x+_485.dx,y:c.y+_485.dy};});if(this.opt.lines){if(this.opt.tension){run.dyn.shadow=s.createPath(dc.curve(_486,this.opt.tension)).setStroke(_485).getStroke();}else{run.dyn.shadow=s.createPolyline(_486).setStroke(_485).getStroke();}}if(this.opt.markers&&_479.marker.shadow){_485=_479.marker.shadow;_484=arr.map(_486,function(c){return this.createPath(run,s,"M"+c.x+" "+c.y+" "+_479.symbol).setStroke(_485).setFill(_485.color);},this);}}if(this.opt.lines&&_47c.length>1){if(_476){if(this.opt.tension){run.dyn.outline=s.createPath(_47f).setStroke(_476).getStroke();}else{run.dyn.outline=s.createPolyline(_47c).setStroke(_476).getStroke();}}if(this.opt.tension){run.dyn.stroke=s.createPath(_47f).setStroke(_475).getStroke();}else{run.dyn.stroke=s.createPolyline(_47c).setStroke(_475).getStroke();}}if(this.opt.markers){_482=new Array(_47c.length);_483=new Array(_47c.length);_476=null;if(_479.marker.outline){_476=dc.makeStroke(_479.marker.outline);_476.width=2*_476.width+(_479.marker.stroke?_479.marker.stroke.width:0);}arr.forEach(_47c,function(c,i){var path="M"+c.x+" "+c.y+" "+_479.symbol;if(_476){_483[i]=this.createPath(run,s,path).setStroke(_476);}_482[i]=this.createPath(run,s,path).setStroke(_479.marker.stroke).setFill(_479.marker.fill);},this);run.dyn.markerFill=_479.marker.fill;run.dyn.markerStroke=_479.marker.stroke;if(_478){arr.forEach(_482,function(s,i){var o={element:"marker",index:i+_47b[seg],run:run,shape:s,outline:_483[i]||null,shadow:_484&&_484[i]||null,cx:_47c[i].x,cy:_47c[i].y};if(typeof _47a[seg][0]=="number"){o.x=i+_47b[seg]+1;o.y=_47a[seg][i];}else{o.x=_47a[seg][i].x;o.y=_47a[seg][i].y;}this._connectEvents(o);_47d[i+_47b[seg]]=o;},this);}else{delete this._eventSeries[run.name];}}}run.dirty=false;}if(this.animate){var _487=this.group;fx.animateTransform(lang.delegate({shape:_487,duration:_46f,transform:[{name:"translate",start:[0,dim.height-_474.b],end:[0,0]},{name:"scale",start:[1,0],end:[1,1]},{name:"original"}]},this.animate)).play();}this.dirty=false;return this;}});});},"dijit/main":function(){define("dijit/main",["dojo/_base/kernel"],function(dojo){return dojo.dijit;});},"dojox/charting/plot2d/Base":function(){define("dojox/charting/plot2d/Base",["dojo/_base/lang","dojo/_base/declare","dojo/_base/connect","../Element","./_PlotEvents","dojo/_base/array","../scaler/primitive","./common","dojox/gfx/fx"],function(lang,_488,hub,_489,_48a,arr,_48b,_48c,fx){return _488("dojox.charting.plot2d.Base",[_489,_48a],{constructor:function(_48d,_48e){this.zoom=null,this.zoomQueue=[];this.lastWindow={vscale:1,hscale:1,xoffset:0,yoffset:0};},clear:function(){this.series=[];this._hAxis=null;this._vAxis=null;this.dirty=true;return this;},setAxis:function(axis){if(axis){this[axis.vertical?"_vAxis":"_hAxis"]=axis;}return this;},toPage:function(_48f){var ah=this._hAxis,av=this._vAxis,sh=ah.getScaler(),sv=av.getScaler(),th=sh.scaler.getTransformerFromModel(sh),tv=sv.scaler.getTransformerFromModel(sv),c=this.chart.getCoords(),o=this.chart.offsets,dim=this.chart.dim;var t=function(_490){var r={};r.x=th(_490[ah.name])+c.x+o.l;r.y=c.y+dim.height-o.b-tv(_490[av.name]);return r;};return _48f?t(_48f):t;},toData:function(_491){var ah=this._hAxis,av=this._vAxis,sh=ah.getScaler(),sv=av.getScaler(),th=sh.scaler.getTransformerFromPlot(sh),tv=sv.scaler.getTransformerFromPlot(sv),c=this.chart.getCoords(),o=this.chart.offsets,dim=this.chart.dim;var t=function(_492){var r={};r[ah.name]=th(_492.x-c.x-o.l);r[av.name]=tv(c.y+dim.height-_492.y-o.b);return r;};return _491?t(_491):t;},addSeries:function(run){this.series.push(run);return this;},getSeriesStats:function(){return _48c.collectSimpleStats(this.series);},calculateAxes:function(dim){this.initializeScalers(dim,this.getSeriesStats());return this;},isDirty:function(){return this.dirty||this._hAxis&&this._hAxis.dirty||this._vAxis&&this._vAxis.dirty;},isDataDirty:function(){return arr.some(this.series,function(item){return item.dirty;});},performZoom:function(dim,_493){var vs=this._vAxis.scale||1,hs=this._hAxis.scale||1,_494=dim.height-_493.b,_495=this._hScaler.bounds,_496=(_495.from-_495.lower)*_495.scale,_497=this._vScaler.bounds,_498=(_497.from-_497.lower)*_497.scale,_499=vs/this.lastWindow.vscale,_49a=hs/this.lastWindow.hscale,_49b=(this.lastWindow.xoffset-_496)/((this.lastWindow.hscale==1)?hs:this.lastWindow.hscale),_49c=(_498-this.lastWindow.yoffset)/((this.lastWindow.vscale==1)?vs:this.lastWindow.vscale),_49d=this.group,anim=fx.animateTransform(lang.delegate({shape:_49d,duration:1200,transform:[{name:"translate",start:[0,0],end:[_493.l*(1-_49a),_494*(1-_499)]},{name:"scale",start:[1,1],end:[_49a,_499]},{name:"original"},{name:"translate",start:[0,0],end:[_49b,_49c]}]},this.zoom));lang.mixin(this.lastWindow,{vscale:vs,hscale:hs,xoffset:_496,yoffset:_498});this.zoomQueue.push(anim);hub.connect(anim,"onEnd",this,function(){this.zoom=null;this.zoomQueue.shift();if(this.zoomQueue.length>0){this.zoomQueue[0].play();}});if(this.zoomQueue.length==1){this.zoomQueue[0].play();}return this;},render:function(dim,_49e){return this;},getRequiredColors:function(){return this.series.length;},initializeScalers:function(dim,_49f){if(this._hAxis){if(!this._hAxis.initialized()){this._hAxis.calculate(_49f.hmin,_49f.hmax,dim.width);}this._hScaler=this._hAxis.getScaler();}else{this._hScaler=_48b.buildScaler(_49f.hmin,_49f.hmax,dim.width);}if(this._vAxis){if(!this._vAxis.initialized()){this._vAxis.calculate(_49f.vmin,_49f.vmax,dim.height);}this._vScaler=this._vAxis.getScaler();}else{this._vScaler=_48b.buildScaler(_49f.vmin,_49f.vmax,dim.height);}return this;}});});},"dojox/charting/action2d/Tooltip":function(){define("dojox/charting/action2d/Tooltip",["dojo/_base/kernel","dijit/Tooltip","dojo/_base/lang","dojo/_base/html","dojo/_base/declare","./PlotAction","dojox/gfx/matrix","dojox/lang/functional","dojox/lang/functional/scan","dojox/lang/functional/fold"],function(dojo,_4a0,lang,html,_4a1,_4a2,m,df,dfs,dff){var _4a3=function(o){var t=o.run&&o.run.data&&o.run.data[o.index];if(t&&typeof t!="number"&&(t.tooltip||t.text)){return t.tooltip||t.text;}if(o.element=="candlestick"){return "<table cellpadding=\"1\" cellspacing=\"0\" border=\"0\" style=\"font-size:0.9em;\">"+"<tr><td>Open:</td><td align=\"right\"><strong>"+o.data.open+"</strong></td></tr>"+"<tr><td>High:</td><td align=\"right\"><strong>"+o.data.high+"</strong></td></tr>"+"<tr><td>Low:</td><td align=\"right\"><strong>"+o.data.low+"</strong></td></tr>"+"<tr><td>Close:</td><td align=\"right\"><strong>"+o.data.close+"</strong></td></tr>"+(o.data.mid!==undefined?"<tr><td>Mid:</td><td align=\"right\"><strong>"+o.data.mid+"</strong></td></tr>":"")+"</table>";}return o.element=="bar"?o.x:o.y;};var pi4=Math.PI/4,pi2=Math.PI/2;return _4a1("dojox.charting.action2d.Tooltip",_4a2,{defaultParams:{text:_4a3},optionalParams:{},constructor:function(_4a4,plot,_4a5){this.text=_4a5&&_4a5.text?_4a5.text:_4a3;this.connect();},process:function(o){if(o.type==="onplotreset"||o.type==="onmouseout"){_4a0.hide(this.aroundRect);this.aroundRect=null;if(o.type==="onplotreset"){delete this.angles;}return;}if(!o.shape||o.type!=="onmouseover"){return;}var _4a6={type:"rect"},_4a7=["after","before"];switch(o.element){case "marker":_4a6.x=o.cx;_4a6.y=o.cy;_4a6.w=_4a6.h=1;break;case "circle":_4a6.x=o.cx-o.cr;_4a6.y=o.cy-o.cr;_4a6.w=_4a6.h=2*o.cr;break;case "column":_4a7=["above","below"];case "bar":_4a6=lang.clone(o.shape.getShape());_4a6.w=_4a6.width;_4a6.h=_4a6.height;break;case "candlestick":_4a6.x=o.x;_4a6.y=o.y;_4a6.w=o.width;_4a6.h=o.height;break;default:if(!this.angles){if(typeof o.run.data[0]=="number"){this.angles=df.map(df.scanl(o.run.data,"+",0),"* 2 * Math.PI / this",df.foldl(o.run.data,"+",0));}else{this.angles=df.map(df.scanl(o.run.data,"a + b.y",0),"* 2 * Math.PI / this",df.foldl(o.run.data,"a + b.y",0));}}var _4a8=m._degToRad(o.plot.opt.startAngle),_4a9=(this.angles[o.index]+this.angles[o.index+1])/2+_4a8;_4a6.x=o.cx+o.cr*Math.cos(_4a9);_4a6.y=o.cy+o.cr*Math.sin(_4a9);_4a6.w=_4a6.h=1;if(_4a9<pi4){}else{if(_4a9<pi2+pi4){_4a7=["below","above"];}else{if(_4a9<Math.PI+pi4){_4a7=["before","after"];}else{if(_4a9<2*Math.PI-pi4){_4a7=["above","below"];}}}}break;}var lt=this.chart.getCoords();_4a6.x+=lt.x;_4a6.y+=lt.y;_4a6.x=Math.round(_4a6.x);_4a6.y=Math.round(_4a6.y);_4a6.w=Math.ceil(_4a6.w);_4a6.h=Math.ceil(_4a6.h);this.aroundRect=_4a6;var _4aa=this.text(o);if(this.chart.getTextDir){var _4ab=(html.style(this.chart.node,"direction")=="rtl");var _4ac=(this.chart.getTextDir(_4aa)=="rtl");}if(_4aa){if(_4ac&&!_4ab){_4a0.show("<span dir = 'rtl'>"+_4aa+"</span>",this.aroundRect,_4a7);}else{if(!_4ac&&_4ab){_4a0.show("<span dir = 'ltr'>"+_4aa+"</span>",this.aroundRect,_4a7);}else{_4a0.show(_4aa,this.aroundRect,_4a7);}}}}});});},"dojox/gfx":function(){define(["dojo/_base/lang","./gfx/_base","./gfx/renderer!"],function(lang,_4ad,_4ae){_4ad.switchTo(_4ae);return _4ad;});},"dojox/gfx/shape":function(){define("dojox/gfx/shape",["./_base","dojo/_base/lang","dojo/_base/declare","dojo/_base/window","dojo/_base/sniff","dojo/_base/connect","dojo/_base/array","dojo/dom-construct","dojo/_base/Color","./matrix"],function(g,lang,_4af,win,has,_4b0,arr,_4b1,_4b2,_4b3){var _4b4=g.shape={};var _4b5={};var _4b6={};_4b4.register=function(_4b7){var t=_4b7.declaredClass.split(".").pop();var i=t in _4b5?++_4b5[t]:((_4b5[t]=0));var uid=t+i;_4b6[uid]=_4b7;return uid;};_4b4.byId=function(id){return _4b6[id];};_4b4.dispose=function(_4b8){delete _4b6[_4b8.getUID()];};_4af("dojox.gfx.shape.Shape",null,{constructor:function(){this.rawNode=null;this.shape=null;this.matrix=null;this.fillStyle=null;this.strokeStyle=null;this.bbox=null;this.parent=null;this.parentMatrix=null;var uid=_4b4.register(this);this.getUID=function(){return uid;};},getNode:function(){return this.rawNode;},getShape:function(){return this.shape;},getTransform:function(){return this.matrix;},getFill:function(){return this.fillStyle;},getStroke:function(){return this.strokeStyle;},getParent:function(){return this.parent;},getBoundingBox:function(){return this.bbox;},getTransformedBoundingBox:function(){var b=this.getBoundingBox();if(!b){return null;}var m=this._getRealMatrix(),gm=_4b3;return [gm.multiplyPoint(m,b.x,b.y),gm.multiplyPoint(m,b.x+b.width,b.y),gm.multiplyPoint(m,b.x+b.width,b.y+b.height),gm.multiplyPoint(m,b.x,b.y+b.height)];},getEventSource:function(){return this.rawNode;},setShape:function(_4b9){this.shape=g.makeParameters(this.shape,_4b9);this.bbox=null;return this;},setFill:function(fill){if(!fill){this.fillStyle=null;return this;}var f=null;if(typeof (fill)=="object"&&"type" in fill){switch(fill.type){case "linear":f=g.makeParameters(g.defaultLinearGradient,fill);break;case "radial":f=g.makeParameters(g.defaultRadialGradient,fill);break;case "pattern":f=g.makeParameters(g.defaultPattern,fill);break;}}else{f=g.normalizeColor(fill);}this.fillStyle=f;return this;},setStroke:function(_4ba){if(!_4ba){this.strokeStyle=null;return this;}if(typeof _4ba=="string"||lang.isArray(_4ba)||_4ba instanceof _4b2){_4ba={color:_4ba};}var s=this.strokeStyle=g.makeParameters(g.defaultStroke,_4ba);s.color=g.normalizeColor(s.color);return this;},setTransform:function(_4bb){this.matrix=_4b3.clone(_4bb?_4b3.normalize(_4bb):_4b3.identity);return this._applyTransform();},_applyTransform:function(){return this;},moveToFront:function(){var p=this.getParent();if(p){p._moveChildToFront(this);this._moveToFront();}return this;},moveToBack:function(){var p=this.getParent();if(p){p._moveChildToBack(this);this._moveToBack();}return this;},_moveToFront:function(){},_moveToBack:function(){},applyRightTransform:function(_4bc){return _4bc?this.setTransform([this.matrix,_4bc]):this;},applyLeftTransform:function(_4bd){return _4bd?this.setTransform([_4bd,this.matrix]):this;},applyTransform:function(_4be){return _4be?this.setTransform([this.matrix,_4be]):this;},removeShape:function(_4bf){if(this.parent){this.parent.remove(this,_4bf);}return this;},_setParent:function(_4c0,_4c1){this.parent=_4c0;return this._updateParentMatrix(_4c1);},_updateParentMatrix:function(_4c2){this.parentMatrix=_4c2?_4b3.clone(_4c2):null;return this._applyTransform();},_getRealMatrix:function(){var m=this.matrix;var p=this.parent;while(p){if(p.matrix){m=_4b3.multiply(p.matrix,m);}p=p.parent;}return m;}});_4b4._eventsProcessing={connect:function(name,_4c3,_4c4){return _4b0.connect(this.getEventSource(),name,_4b4.fixCallback(this,g.fixTarget,_4c3,_4c4));},disconnect:function(_4c5){_4b0.disconnect(_4c5);}};_4b4.fixCallback=function(_4c6,_4c7,_4c8,_4c9){if(!_4c9){_4c9=_4c8;_4c8=null;}if(lang.isString(_4c9)){_4c8=_4c8||win.global;if(!_4c8[_4c9]){throw (["dojox.gfx.shape.fixCallback: scope[\"",_4c9,"\"] is null (scope=\"",_4c8,"\")"].join(""));}return function(e){return _4c7(e,_4c6)?_4c8[_4c9].apply(_4c8,arguments||[]):undefined;};}return !_4c8?function(e){return _4c7(e,_4c6)?_4c9.apply(_4c8,arguments):undefined;}:function(e){return _4c7(e,_4c6)?_4c9.apply(_4c8,arguments||[]):undefined;};};lang.extend(_4b4.Shape,_4b4._eventsProcessing);_4b4.Container={_init:function(){this.children=[];},openBatch:function(){},closeBatch:function(){},add:function(_4ca){var _4cb=_4ca.getParent();if(_4cb){_4cb.remove(_4ca,true);}this.children.push(_4ca);return _4ca._setParent(this,this._getRealMatrix());},remove:function(_4cc,_4cd){for(var i=0;i<this.children.length;++i){if(this.children[i]==_4cc){if(_4cd){}else{_4cc.parent=null;_4cc.parentMatrix=null;}this.children.splice(i,1);break;}}return this;},clear:function(){var _4ce;for(var i=0;i<this.children.length;++i){_4ce=this.children[i];_4ce.parent=null;_4ce.parentMatrix=null;}this.children=[];return this;},_moveChildToFront:function(_4cf){for(var i=0;i<this.children.length;++i){if(this.children[i]==_4cf){this.children.splice(i,1);this.children.push(_4cf);break;}}return this;},_moveChildToBack:function(_4d0){for(var i=0;i<this.children.length;++i){if(this.children[i]==_4d0){this.children.splice(i,1);this.children.unshift(_4d0);break;}}return this;}};_4af("dojox.gfx.shape.Surface",null,{constructor:function(){this.rawNode=null;this._parent=null;this._nodes=[];this._events=[];},destroy:function(){arr.forEach(this._nodes,_4b1.destroy);this._nodes=[];arr.forEach(this._events,_4b0.disconnect);this._events=[];this.rawNode=null;if(has("ie")){while(this._parent.lastChild){_4b1.destroy(this._parent.lastChild);}}else{this._parent.innerHTML="";}this._parent=null;},getEventSource:function(){return this.rawNode;},_getRealMatrix:function(){return null;},isLoaded:true,onLoad:function(_4d1){},whenLoaded:function(_4d2,_4d3){var f=lang.hitch(_4d2,_4d3);if(this.isLoaded){f(this);}else{var h=_4b0.connect(this,"onLoad",function(_4d4){_4b0.disconnect(h);f(_4d4);});}}});lang.extend(_4b4.Surface,_4b4._eventsProcessing);_4af("dojox.gfx.Point",null,{});_4af("dojox.gfx.Rectangle",null,{});_4af("dojox.gfx.shape.Rect",_4b4.Shape,{constructor:function(_4d5){this.shape=g.getDefault("Rect");this.rawNode=_4d5;},getBoundingBox:function(){return this.shape;}});_4af("dojox.gfx.shape.Ellipse",_4b4.Shape,{constructor:function(_4d6){this.shape=g.getDefault("Ellipse");this.rawNode=_4d6;},getBoundingBox:function(){if(!this.bbox){var _4d7=this.shape;this.bbox={x:_4d7.cx-_4d7.rx,y:_4d7.cy-_4d7.ry,width:2*_4d7.rx,height:2*_4d7.ry};}return this.bbox;}});_4af("dojox.gfx.shape.Circle",_4b4.Shape,{constructor:function(_4d8){this.shape=g.getDefault("Circle");this.rawNode=_4d8;},getBoundingBox:function(){if(!this.bbox){var _4d9=this.shape;this.bbox={x:_4d9.cx-_4d9.r,y:_4d9.cy-_4d9.r,width:2*_4d9.r,height:2*_4d9.r};}return this.bbox;}});_4af("dojox.gfx.shape.Line",_4b4.Shape,{constructor:function(_4da){this.shape=g.getDefault("Line");this.rawNode=_4da;},getBoundingBox:function(){if(!this.bbox){var _4db=this.shape;this.bbox={x:Math.min(_4db.x1,_4db.x2),y:Math.min(_4db.y1,_4db.y2),width:Math.abs(_4db.x2-_4db.x1),height:Math.abs(_4db.y2-_4db.y1)};}return this.bbox;}});_4af("dojox.gfx.shape.Polyline",_4b4.Shape,{constructor:function(_4dc){this.shape=g.getDefault("Polyline");this.rawNode=_4dc;},setShape:function(_4dd,_4de){if(_4dd&&_4dd instanceof Array){this.inherited(arguments,[{points:_4dd}]);if(_4de&&this.shape.points.length){this.shape.points.push(this.shape.points[0]);}}else{this.inherited(arguments,[_4dd]);}return this;},_normalizePoints:function(){var p=this.shape.points,l=p&&p.length;if(l&&typeof p[0]=="number"){var _4df=[];for(var i=0;i<l;i+=2){_4df.push({x:p[i],y:p[i+1]});}this.shape.points=_4df;}},getBoundingBox:function(){if(!this.bbox&&this.shape.points.length){var p=this.shape.points;var l=p.length;var t=p[0];var bbox={l:t.x,t:t.y,r:t.x,b:t.y};for(var i=1;i<l;++i){t=p[i];if(bbox.l>t.x){bbox.l=t.x;}if(bbox.r<t.x){bbox.r=t.x;}if(bbox.t>t.y){bbox.t=t.y;}if(bbox.b<t.y){bbox.b=t.y;}}this.bbox={x:bbox.l,y:bbox.t,width:bbox.r-bbox.l,height:bbox.b-bbox.t};}return this.bbox;}});_4af("dojox.gfx.shape.Image",_4b4.Shape,{constructor:function(_4e0){this.shape=g.getDefault("Image");this.rawNode=_4e0;},getBoundingBox:function(){return this.shape;},setStroke:function(){return this;},setFill:function(){return this;}});_4af("dojox.gfx.shape.Text",_4b4.Shape,{constructor:function(_4e1){this.fontStyle=null;this.shape=g.getDefault("Text");this.rawNode=_4e1;},getFont:function(){return this.fontStyle;},setFont:function(_4e2){this.fontStyle=typeof _4e2=="string"?g.splitFontString(_4e2):g.makeParameters(g.defaultFont,_4e2);this._setFont();return this;}});_4b4.Creator={createShape:function(_4e3){switch(_4e3.type){case g.defaultPath.type:return this.createPath(_4e3);case g.defaultRect.type:return this.createRect(_4e3);case g.defaultCircle.type:return this.createCircle(_4e3);case g.defaultEllipse.type:return this.createEllipse(_4e3);case g.defaultLine.type:return this.createLine(_4e3);case g.defaultPolyline.type:return this.createPolyline(_4e3);case g.defaultImage.type:return this.createImage(_4e3);case g.defaultText.type:return this.createText(_4e3);case g.defaultTextPath.type:return this.createTextPath(_4e3);}return null;},createGroup:function(){return this.createObject(g.Group);},createRect:function(rect){return this.createObject(g.Rect,rect);},createEllipse:function(_4e4){return this.createObject(g.Ellipse,_4e4);},createCircle:function(_4e5){return this.createObject(g.Circle,_4e5);},createLine:function(line){return this.createObject(g.Line,line);},createPolyline:function(_4e6){return this.createObject(g.Polyline,_4e6);},createImage:function(_4e7){return this.createObject(g.Image,_4e7);},createText:function(text){return this.createObject(g.Text,text);},createPath:function(path){return this.createObject(g.Path,path);},createTextPath:function(text){return this.createObject(g.TextPath,{}).setText(text);},createObject:function(_4e8,_4e9){return null;}};return _4b4;});},"dojox/charting/Chart2D":function(){define("dojox/charting/Chart2D",["dojo/_base/kernel","dojox","./Chart","./axis2d/Default","./axis2d/Invisible","./plot2d/Default","./plot2d/Lines","./plot2d/Areas","./plot2d/Markers","./plot2d/MarkersOnly","./plot2d/Scatter","./plot2d/Stacked","./plot2d/StackedLines","./plot2d/StackedAreas","./plot2d/Columns","./plot2d/StackedColumns","./plot2d/ClusteredColumns","./plot2d/Bars","./plot2d/StackedBars","./plot2d/ClusteredBars","./plot2d/Grid","./plot2d/Pie","./plot2d/Bubble","./plot2d/Candlesticks","./plot2d/OHLC","./plot2d/Spider"],function(dojo,_4ea,_4eb){dojo.deprecated("dojox.charting.Chart2D","Use dojo.charting.Chart instead and require all other components explicitly","2.0");return _4ea.charting.Chart2D=_4eb;});},"dojox/charting/scaler/linear":function(){define("dojox/charting/scaler/linear",["dojo/_base/lang","./common"],function(lang,_4ec){var _4ed=lang.getObject("dojox.charting.scaler.linear",true);var _4ee=3,_4ef=_4ec.findString,_4f0=_4ec.getNumericLabel;var _4f1=function(min,max,_4f2,_4f3,_4f4,_4f5,span){_4f2=lang.delegate(_4f2);if(!_4f3){if(_4f2.fixUpper=="major"){_4f2.fixUpper="minor";}if(_4f2.fixLower=="major"){_4f2.fixLower="minor";}}if(!_4f4){if(_4f2.fixUpper=="minor"){_4f2.fixUpper="micro";}if(_4f2.fixLower=="minor"){_4f2.fixLower="micro";}}if(!_4f5){if(_4f2.fixUpper=="micro"){_4f2.fixUpper="none";}if(_4f2.fixLower=="micro"){_4f2.fixLower="none";}}var _4f6=_4ef(_4f2.fixLower,["major"])?Math.floor(_4f2.min/_4f3)*_4f3:_4ef(_4f2.fixLower,["minor"])?Math.floor(_4f2.min/_4f4)*_4f4:_4ef(_4f2.fixLower,["micro"])?Math.floor(_4f2.min/_4f5)*_4f5:_4f2.min,_4f7=_4ef(_4f2.fixUpper,["major"])?Math.ceil(_4f2.max/_4f3)*_4f3:_4ef(_4f2.fixUpper,["minor"])?Math.ceil(_4f2.max/_4f4)*_4f4:_4ef(_4f2.fixUpper,["micro"])?Math.ceil(_4f2.max/_4f5)*_4f5:_4f2.max;if(_4f2.useMin){min=_4f6;}if(_4f2.useMax){max=_4f7;}var _4f8=(!_4f3||_4f2.useMin&&_4ef(_4f2.fixLower,["major"]))?min:Math.ceil(min/_4f3)*_4f3,_4f9=(!_4f4||_4f2.useMin&&_4ef(_4f2.fixLower,["major","minor"]))?min:Math.ceil(min/_4f4)*_4f4,_4fa=(!_4f5||_4f2.useMin&&_4ef(_4f2.fixLower,["major","minor","micro"]))?min:Math.ceil(min/_4f5)*_4f5,_4fb=!_4f3?0:(_4f2.useMax&&_4ef(_4f2.fixUpper,["major"])?Math.round((max-_4f8)/_4f3):Math.floor((max-_4f8)/_4f3))+1,_4fc=!_4f4?0:(_4f2.useMax&&_4ef(_4f2.fixUpper,["major","minor"])?Math.round((max-_4f9)/_4f4):Math.floor((max-_4f9)/_4f4))+1,_4fd=!_4f5?0:(_4f2.useMax&&_4ef(_4f2.fixUpper,["major","minor","micro"])?Math.round((max-_4fa)/_4f5):Math.floor((max-_4fa)/_4f5))+1,_4fe=_4f4?Math.round(_4f3/_4f4):0,_4ff=_4f5?Math.round(_4f4/_4f5):0,_500=_4f3?Math.floor(Math.log(_4f3)/Math.LN10):0,_501=_4f4?Math.floor(Math.log(_4f4)/Math.LN10):0,_502=span/(max-min);if(!isFinite(_502)){_502=1;}return {bounds:{lower:_4f6,upper:_4f7,from:min,to:max,scale:_502,span:span},major:{tick:_4f3,start:_4f8,count:_4fb,prec:_500},minor:{tick:_4f4,start:_4f9,count:_4fc,prec:_501},micro:{tick:_4f5,start:_4fa,count:_4fd,prec:0},minorPerMajor:_4fe,microPerMinor:_4ff,scaler:_4ed};};return lang.mixin(_4ed,{buildScaler:function(min,max,span,_503){var h={fixUpper:"none",fixLower:"none",natural:false};if(_503){if("fixUpper" in _503){h.fixUpper=String(_503.fixUpper);}if("fixLower" in _503){h.fixLower=String(_503.fixLower);}if("natural" in _503){h.natural=Boolean(_503.natural);}}if("min" in _503){min=_503.min;}if("max" in _503){max=_503.max;}if(_503.includeZero){if(min>0){min=0;}if(max<0){max=0;}}h.min=min;h.useMin=true;h.max=max;h.useMax=true;if("from" in _503){min=_503.from;h.useMin=false;}if("to" in _503){max=_503.to;h.useMax=false;}if(max<=min){return _4f1(min,max,h,0,0,0,span);}var mag=Math.floor(Math.log(max-min)/Math.LN10),_504=_503&&("majorTickStep" in _503)?_503.majorTickStep:Math.pow(10,mag),_505=0,_506=0,_507;if(_503&&("minorTickStep" in _503)){_505=_503.minorTickStep;}else{do{_505=_504/10;if(!h.natural||_505>0.9){_507=_4f1(min,max,h,_504,_505,0,span);if(_507.bounds.scale*_507.minor.tick>_4ee){break;}}_505=_504/5;if(!h.natural||_505>0.9){_507=_4f1(min,max,h,_504,_505,0,span);if(_507.bounds.scale*_507.minor.tick>_4ee){break;}}_505=_504/2;if(!h.natural||_505>0.9){_507=_4f1(min,max,h,_504,_505,0,span);if(_507.bounds.scale*_507.minor.tick>_4ee){break;}}return _4f1(min,max,h,_504,0,0,span);}while(false);}if(_503&&("microTickStep" in _503)){_506=_503.microTickStep;_507=_4f1(min,max,h,_504,_505,_506,span);}else{do{_506=_505/10;if(!h.natural||_506>0.9){_507=_4f1(min,max,h,_504,_505,_506,span);if(_507.bounds.scale*_507.micro.tick>_4ee){break;}}_506=_505/5;if(!h.natural||_506>0.9){_507=_4f1(min,max,h,_504,_505,_506,span);if(_507.bounds.scale*_507.micro.tick>_4ee){break;}}_506=_505/2;if(!h.natural||_506>0.9){_507=_4f1(min,max,h,_504,_505,_506,span);if(_507.bounds.scale*_507.micro.tick>_4ee){break;}}_506=0;}while(false);}return _506?_507:_4f1(min,max,h,_504,_505,0,span);},buildTicks:function(_508,_509){var step,next,tick,_50a=_508.major.start,_50b=_508.minor.start,_50c=_508.micro.start;if(_509.microTicks&&_508.micro.tick){step=_508.micro.tick,next=_50c;}else{if(_509.minorTicks&&_508.minor.tick){step=_508.minor.tick,next=_50b;}else{if(_508.major.tick){step=_508.major.tick,next=_50a;}else{return null;}}}var _50d=1/_508.bounds.scale;if(_508.bounds.to<=_508.bounds.from||isNaN(_50d)||!isFinite(_50d)||step<=0||isNaN(step)||!isFinite(step)){return null;}var _50e=[],_50f=[],_510=[];while(next<=_508.bounds.to+_50d){if(Math.abs(_50a-next)<step/2){tick={value:_50a};if(_509.majorLabels){tick.label=_4f0(_50a,_508.major.prec,_509);}_50e.push(tick);_50a+=_508.major.tick;_50b+=_508.minor.tick;_50c+=_508.micro.tick;}else{if(Math.abs(_50b-next)<step/2){if(_509.minorTicks){tick={value:_50b};if(_509.minorLabels&&(_508.minMinorStep<=_508.minor.tick*_508.bounds.scale)){tick.label=_4f0(_50b,_508.minor.prec,_509);}_50f.push(tick);}_50b+=_508.minor.tick;_50c+=_508.micro.tick;}else{if(_509.microTicks){_510.push({value:_50c});}_50c+=_508.micro.tick;}}next+=step;}return {major:_50e,minor:_50f,micro:_510};},getTransformerFromModel:function(_511){var _512=_511.bounds.from,_513=_511.bounds.scale;return function(x){return (x-_512)*_513;};},getTransformerFromPlot:function(_514){var _515=_514.bounds.from,_516=_514.bounds.scale;return function(x){return x/_516+_515;};}});});},"dojox/gfx/renderer":function(){define("dojox/gfx/renderer",["./_base","dojo/_base/lang","dojo/_base/sniff","dojo/_base/window","dojo/_base/config"],function(g,lang,has,win,_517){var _518=null;return {load:function(id,_519,load){if(_518&&id!="force"){load(_518);return;}var _51a=_517.forceGfxRenderer,_51b=!_51a&&(lang.isString(_517.gfxRenderer)?_517.gfxRenderer:"svg,vml,canvas,silverlight").split(","),_51c,_51d;while(!_51a&&_51b.length){switch(_51b.shift()){case "svg":if("SVGAngle" in win.global){_51a="svg";}break;case "vml":if(has("ie")){_51a="vml";}break;case "silverlight":try{if(has("ie")){_51c=new ActiveXObject("AgControl.AgControl");if(_51c&&_51c.IsVersionSupported("1.0")){_51d=true;}}else{if(navigator.plugins["Silverlight Plug-In"]){_51d=true;}}}catch(e){_51d=false;}finally{_51c=null;}if(_51d){_51a="silverlight";}break;case "canvas":if(win.global.CanvasRenderingContext2D){_51a="canvas";}break;}}if(_51a==="canvas"&&_517.canvasEvents!==false){_51a="canvasWithEvents";}if(_517.isDebug){}function _51e(){_519(["dojox/gfx/"+_51a],function(_51f){g.renderer=_51a;_518=_51f;load(_51f);});};if(_51a=="svg"&&typeof window.svgweb!="undefined"){window.svgweb.addOnLoad(_51e);}else{_51e();}}};});},"dojox/charting/widget/Chart":function(){define("dojox/charting/widget/Chart",["dojo/_base/kernel","dojo/_base/lang","dojo/_base/array","dojo/_base/html","dojo/_base/declare","dojo/query","dijit/_Widget","../Chart","dojox/lang/utils","dojox/lang/functional","dojox/lang/functional/lambda","dijit/_base/manager"],function(_520,lang,arr,html,_521,_522,_523,_524,du,df,dfl){var _525,_526,_527,_528,_529,_52a=function(o){return o;},dc=lang.getObject("dojox.charting");var _52b=_521("dojox.charting.widget.Chart",_523,{theme:null,margins:null,stroke:undefined,fill:undefined,buildRendering:function(){this.inherited(arguments);n=this.domNode;var axes=_522("> .axis",n).map(_526).filter(_52a),_52c=_522("> .plot",n).map(_527).filter(_52a),_52d=_522("> .action",n).map(_528).filter(_52a),_52e=_522("> .series",n).map(_529).filter(_52a);n.innerHTML="";var c=this.chart=new _524(n,{margins:this.margins,stroke:this.stroke,fill:this.fill,textDir:this.textDir});if(this.theme){c.setTheme(this.theme);}axes.forEach(function(axis){c.addAxis(axis.name,axis.kwArgs);});_52c.forEach(function(plot){c.addPlot(plot.name,plot.kwArgs);});this.actions=_52d.map(function(_52f){return new _52f.action(c,_52f.plot,_52f.kwArgs);});var _530=df.foldl(_52e,function(_531,_532){if(_532.type=="data"){c.addSeries(_532.name,_532.data,_532.kwArgs);_531=true;}else{c.addSeries(_532.name,[0],_532.kwArgs);var kw={};du.updateWithPattern(kw,_532.kwArgs,{"query":"","queryOptions":null,"start":0,"count":1},true);if(_532.kwArgs.sort){kw.sort=lang.clone(_532.kwArgs.sort);}lang.mixin(kw,{onComplete:function(data){var _533;if("valueFn" in _532.kwArgs){var fn=_532.kwArgs.valueFn;_533=arr.map(data,function(x){return fn(_532.data.getValue(x,_532.field,0));});}else{_533=arr.map(data,function(x){return _532.data.getValue(x,_532.field,0);});}c.addSeries(_532.name,_533,_532.kwArgs).render();}});_532.data.fetch(kw);}return _531;},false);if(_530){c.render();}},destroy:function(){this.chart.destroy();this.inherited(arguments);},resize:function(box){this.chart.resize(box);}});_525=function(node,type,kw){var dp=eval("("+type+".prototype.defaultParams)");var x,attr;for(x in dp){if(x in kw){continue;}attr=node.getAttribute(x);kw[x]=du.coerceType(dp[x],attr==null||typeof attr=="undefined"?dp[x]:attr);}var op=eval("("+type+".prototype.optionalParams)");for(x in op){if(x in kw){continue;}attr=node.getAttribute(x);if(attr!=null){kw[x]=du.coerceType(op[x],attr);}}};_526=function(node){var name=node.getAttribute("name"),type=node.getAttribute("type");if(!name){return null;}var o={name:name,kwArgs:{}},kw=o.kwArgs;if(type){if(dc.axis2d[type]){type=dojo._scopeName+"x.charting.axis2d."+type;}var axis=eval("("+type+")");if(axis){kw.type=axis;}}else{type=dojo._scopeName+"x.charting.axis2d.Default";}_525(node,type,kw);if(kw.font||kw.fontColor){if(!kw.tick){kw.tick={};}if(kw.font){kw.tick.font=kw.font;}if(kw.fontColor){kw.tick.fontColor=kw.fontColor;}}return o;};_527=function(node){var name=node.getAttribute("name"),type=node.getAttribute("type");if(!name){return null;}var o={name:name,kwArgs:{}},kw=o.kwArgs;if(type){if(dc.plot2d&&dc.plot2d[type]){type=dojo._scopeName+"x.charting.plot2d."+type;}var plot=eval("("+type+")");if(plot){kw.type=plot;}}else{type=dojo._scopeName+"x.charting.plot2d.Default";}_525(node,type,kw);return o;};_528=function(node){var plot=node.getAttribute("plot"),type=node.getAttribute("type");if(!plot){plot="default";}var o={plot:plot,kwArgs:{}},kw=o.kwArgs;if(type){if(dc.action2d[type]){type=dojo._scopeName+"x.charting.action2d."+type;}var _534=eval("("+type+")");if(!_534){return null;}o.action=_534;}else{return null;}_525(node,type,kw);return o;};_529=function(node){var ga=lang.partial(html.attr,node);var name=ga("name");if(!name){return null;}var o={name:name,kwArgs:{}},kw=o.kwArgs,t;t=ga("plot");if(t!=null){kw.plot=t;}t=ga("marker");if(t!=null){kw.marker=t;}t=ga("stroke");if(t!=null){kw.stroke=eval("("+t+")");}t=ga("outline");if(t!=null){kw.outline=eval("("+t+")");}t=ga("shadow");if(t!=null){kw.shadow=eval("("+t+")");}t=ga("fill");if(t!=null){kw.fill=eval("("+t+")");}t=ga("font");if(t!=null){kw.font=t;}t=ga("fontColor");if(t!=null){kw.fontColor=eval("("+t+")");}t=ga("legend");if(t!=null){kw.legend=t;}t=ga("data");if(t!=null){o.type="data";o.data=t?arr.map(String(t).split(","),Number):[];return o;}t=ga("array");if(t!=null){o.type="data";o.data=eval("("+t+")");return o;}t=ga("store");if(t!=null){o.type="store";o.data=eval("("+t+")");t=ga("field");o.field=t!=null?t:"value";t=ga("query");if(!!t){kw.query=t;}t=ga("queryOptions");if(!!t){kw.queryOptions=eval("("+t+")");}t=ga("start");if(!!t){kw.start=Number(t);}t=ga("count");if(!!t){kw.count=Number(t);}t=ga("sort");if(!!t){kw.sort=eval("("+t+")");}t=ga("valueFn");if(!!t){kw.valueFn=dfl.lambda(t);}return o;}return null;};return _52b;});},"dojox/lang/functional":function(){define("dojox/lang/functional",["./functional/lambda","./functional/array","./functional/object"],function(df){return df;});},"dojox/charting/scaler/common":function(){define("dojox/charting/scaler/common",["dojo/_base/lang"],function(lang){var eq=function(a,b){return Math.abs(a-b)<=0.000001*(Math.abs(a)+Math.abs(b));};var _535=lang.getObject("dojox.charting.scaler.common",true);var _536={};return lang.mixin(_535,{doIfLoaded:function(_537,_538,_539){if(_536[_537]==undefined){try{_536[_537]=require(_537);}catch(e){_536[_537]=null;}}if(_536[_537]){return _538(_536[_537]);}else{return _539();}},findString:function(val,text){val=val.toLowerCase();for(var i=0;i<text.length;++i){if(val==text[i]){return true;}}return false;},getNumericLabel:function(_53a,_53b,_53c){var def="";_535.doIfLoaded("dojo/number",function(_53d){def=(_53c.fixed?_53d.format(_53a,{places:_53b<0?-_53b:0}):_53d.format(_53a))||"";},function(){def=_53c.fixed?_53a.toFixed(_53b<0?-_53b:0):_53a.toString();});if(_53c.labelFunc){var r=_53c.labelFunc(def,_53a,_53b);if(r){return r;}}if(_53c.labels){var l=_53c.labels,lo=0,hi=l.length;while(lo<hi){var mid=Math.floor((lo+hi)/2),val=l[mid].value;if(val<_53a){lo=mid+1;}else{hi=mid;}}if(lo<l.length&&eq(l[lo].value,_53a)){return l[lo].text;}--lo;if(lo>=0&&lo<l.length&&eq(l[lo].value,_53a)){return l[lo].text;}lo+=2;if(lo<l.length&&eq(l[lo].value,_53a)){return l[lo].text;}}return def;}});});},"dojox/charting/axis2d/common":function(){define("dojox/charting/axis2d/common",["dojo/_base/lang","dojo/_base/html","dojo/_base/window","dojo/dom-geometry","dojox/gfx"],function(lang,html,win,_53e,g){var _53f=lang.getObject("dojox.charting.axis2d.common",true);var _540=function(s){s.marginLeft="0px";s.marginTop="0px";s.marginRight="0px";s.marginBottom="0px";s.paddingLeft="0px";s.paddingTop="0px";s.paddingRight="0px";s.paddingBottom="0px";s.borderLeftWidth="0px";s.borderTopWidth="0px";s.borderRightWidth="0px";s.borderBottomWidth="0px";};var _541=function(n){if(n["getBoundingClientRect"]){var bcr=n.getBoundingClientRect();return bcr.width||(bcr.right-bcr.left);}else{return _53e.getMarginBox(n).w;}};return lang.mixin(_53f,{createText:{gfx:function(_542,_543,x,y,_544,text,font,_545){return _543.createText({x:x,y:y,text:text,align:_544}).setFont(font).setFill(_545);},html:function(_546,_547,x,y,_548,text,font,_549,_54a){var p=win.doc.createElement("div"),s=p.style,_54b;if(_546.getTextDir){p.dir=_546.getTextDir(text);}_540(s);s.font=font;p.innerHTML=String(text).replace(/\s/g," ");s.color=_549;s.position="absolute";s.left="-10000px";win.body().appendChild(p);var size=g.normalizedLength(g.splitFontString(font).size);if(!_54a){_54b=_541(p);}if(p.dir=="rtl"){x+=_54a?_54a:_54b;}win.body().removeChild(p);s.position="relative";if(_54a){s.width=_54a+"px";switch(_548){case "middle":s.textAlign="center";s.left=(x-_54a/2)+"px";break;case "end":s.textAlign="right";s.left=(x-_54a)+"px";break;default:s.left=x+"px";s.textAlign="left";break;}}else{switch(_548){case "middle":s.left=Math.floor(x-_54b/2)+"px";break;case "end":s.left=Math.floor(x-_54b)+"px";break;default:s.left=Math.floor(x)+"px";break;}}s.top=Math.floor(y-size)+"px";s.whiteSpace="nowrap";var wrap=win.doc.createElement("div"),w=wrap.style;_540(w);w.width="0px";w.height="0px";wrap.appendChild(p);_546.node.insertBefore(wrap,_546.node.firstChild);return wrap;}}});});},"dijit/_TemplatedMixin":function(){define("dijit/_TemplatedMixin",["dojo/_base/lang","dojo/touch","./_WidgetBase","dojo/string","dojo/cache","dojo/_base/array","dojo/_base/declare","dojo/dom-construct","dojo/_base/sniff","dojo/_base/unload","dojo/_base/window"],function(lang,_54c,_54d,_54e,_54f,_550,_551,_552,has,_553,win){var _554=_551("dijit._TemplatedMixin",null,{templateString:null,templatePath:null,_skipNodeCache:false,_earlyTemplatedStartup:false,constructor:function(){this._attachPoints=[];this._attachEvents=[];},_stringRepl:function(tmpl){var _555=this.declaredClass,_556=this;return _54e.substitute(tmpl,this,function(_557,key){if(key.charAt(0)=="!"){_557=lang.getObject(key.substr(1),false,_556);}if(typeof _557=="undefined"){throw new Error(_555+" template:"+key);}if(_557==null){return "";}return key.charAt(0)=="!"?_557:_557.toString().replace(/"/g,""");},this);},buildRendering:function(){if(!this.templateString){this.templateString=_54f(this.templatePath,{sanitize:true});}var _558=_554.getCachedTemplate(this.templateString,this._skipNodeCache);var node;if(lang.isString(_558)){node=_552.toDom(this._stringRepl(_558));if(node.nodeType!=1){throw new Error("Invalid template: "+_558);}}else{node=_558.cloneNode(true);}this.domNode=node;this.inherited(arguments);this._attachTemplateNodes(node,function(n,p){return n.getAttribute(p);});this._beforeFillContent();this._fillContent(this.srcNodeRef);},_beforeFillContent:function(){},_fillContent:function(_559){var dest=this.containerNode;if(_559&&dest){while(_559.hasChildNodes()){dest.appendChild(_559.firstChild);}}},_attachTemplateNodes:function(_55a,_55b){var _55c=lang.isArray(_55a)?_55a:(_55a.all||_55a.getElementsByTagName("*"));var x=lang.isArray(_55a)?0:-1;for(;x<_55c.length;x++){var _55d=(x==-1)?_55a:_55c[x];if(this.widgetsInTemplate&&(_55b(_55d,"dojoType")||_55b(_55d,"data-dojo-type"))){continue;}var _55e=_55b(_55d,"dojoAttachPoint")||_55b(_55d,"data-dojo-attach-point");if(_55e){var _55f,_560=_55e.split(/\s*,\s*/);while((_55f=_560.shift())){if(lang.isArray(this[_55f])){this[_55f].push(_55d);}else{this[_55f]=_55d;}this._attachPoints.push(_55f);}}var _561=_55b(_55d,"dojoAttachEvent")||_55b(_55d,"data-dojo-attach-event");if(_561){var _562,_563=_561.split(/\s*,\s*/);var trim=lang.trim;while((_562=_563.shift())){if(_562){var _564=null;if(_562.indexOf(":")!=-1){var _565=_562.split(":");_562=trim(_565[0]);_564=trim(_565[1]);}else{_562=trim(_562);}if(!_564){_564=_562;}this._attachEvents.push(this.connect(_55d,_54c[_562]||_562,_564));}}}}},destroyRendering:function(){_550.forEach(this._attachPoints,function(_566){delete this[_566];},this);this._attachPoints=[];_550.forEach(this._attachEvents,this.disconnect,this);this._attachEvents=[];this.inherited(arguments);}});_554._templateCache={};_554.getCachedTemplate=function(_567,_568){var _569=_554._templateCache;var key=_567;var _56a=_569[key];if(_56a){try{if(!_56a.ownerDocument||_56a.ownerDocument==win.doc){return _56a;}}catch(e){}_552.destroy(_56a);}_567=_54e.trim(_567);if(_568||_567.match(/\$\{([^\}]+)\}/g)){return (_569[key]=_567);}else{var node=_552.toDom(_567);if(node.nodeType!=1){throw new Error("Invalid template: "+_567);}return (_569[key]=node);}};if(has("ie")){_553.addOnWindowUnload(function(){var _56b=_554._templateCache;for(var key in _56b){var _56c=_56b[key];if(typeof _56c=="object"){_552.destroy(_56c);}delete _56b[key];}});}lang.extend(_54d,{dojoAttachEvent:"",dojoAttachPoint:""});return _554;});},"dojox/lang/functional/object":function(){define(["dojo/_base/kernel","dojo/_base/lang","dojo/_base/window","./lambda"],function(dojo,lang,win,df){var _56d={};lang.mixin(df,{keys:function(obj){var t=[];for(var i in obj){if(!(i in _56d)){t.push(i);}}return t;},values:function(obj){var t=[];for(var i in obj){if(!(i in _56d)){t.push(obj[i]);}}return t;},filterIn:function(obj,f,o){o=o||win.global;f=df.lambda(f);var t={},v,i;for(i in obj){if(!(i in _56d)){v=obj[i];if(f.call(o,v,i,obj)){t[i]=v;}}}return t;},forIn:function(obj,f,o){o=o||win.global;f=df.lambda(f);for(var i in obj){if(!(i in _56d)){f.call(o,obj[i],i,obj);}}return o;},mapIn:function(obj,f,o){o=o||win.global;f=df.lambda(f);var t={},i;for(i in obj){if(!(i in _56d)){t[i]=f.call(o,obj[i],i,obj);}}return t;}});return df;});},"dojo/window":function(){define(["./_base/lang","./_base/sniff","./_base/window","./dom","./dom-geometry","./dom-style"],function(lang,has,_56e,dom,geom,_56f){var _570=lang.getObject("dojo.window",true);_570.getBox=function(){var _571=(_56e.doc.compatMode=="BackCompat")?_56e.body():_56e.doc.documentElement,_572=geom.docScroll(),w,h;if(has("touch")){var _573=_56e.doc.parentWindow||_56e.doc.defaultView;w=_573.innerWidth||_571.clientWidth;h=_573.innerHeight||_571.clientHeight;}else{w=_571.clientWidth;h=_571.clientHeight;}return {l:_572.x,t:_572.y,w:w,h:h};};_570.get=function(doc){if(has("ie")&&_570!==document.parentWindow){doc.parentWindow.execScript("document._parentWindow = window;","Javascript");var win=doc._parentWindow;doc._parentWindow=null;return win;}return doc.parentWindow||doc.defaultView;};_570.scrollIntoView=function(node,pos){try{node=dom.byId(node);var doc=node.ownerDocument||_56e.doc,body=doc.body||_56e.body(),html=doc.documentElement||body.parentNode,isIE=has("ie"),isWK=has("webkit");if((!(has("mozilla")||isIE||isWK||has("opera"))||node==body||node==html)&&(typeof node.scrollIntoView!="undefined")){node.scrollIntoView(false);return;}var _574=doc.compatMode=="BackCompat",_575=(isIE>=9&&node.ownerDocument.parentWindow.frameElement)?((html.clientHeight>0&&html.clientWidth>0&&(body.clientHeight==0||body.clientWidth==0||body.clientHeight>html.clientHeight||body.clientWidth>html.clientWidth))?html:body):(_574?body:html),_576=isWK?body:_575,_577=_575.clientWidth,_578=_575.clientHeight,rtl=!geom.isBodyLtr(),_579=pos||geom.position(node),el=node.parentNode,_57a=function(el){return ((isIE<=6||(isIE&&_574))?false:(_56f.get(el,"position").toLowerCase()=="fixed"));};if(_57a(node)){return;}while(el){if(el==body){el=_576;}var _57b=geom.position(el),_57c=_57a(el);if(el==_576){_57b.w=_577;_57b.h=_578;if(_576==html&&isIE&&rtl){_57b.x+=_576.offsetWidth-_57b.w;}if(_57b.x<0||!isIE){_57b.x=0;}if(_57b.y<0||!isIE){_57b.y=0;}}else{var pb=geom.getPadBorderExtents(el);_57b.w-=pb.w;_57b.h-=pb.h;_57b.x+=pb.l;_57b.y+=pb.t;var _57d=el.clientWidth,_57e=_57b.w-_57d;if(_57d>0&&_57e>0){_57b.w=_57d;_57b.x+=(rtl&&(isIE||el.clientLeft>pb.l))?_57e:0;}_57d=el.clientHeight;_57e=_57b.h-_57d;if(_57d>0&&_57e>0){_57b.h=_57d;}}if(_57c){if(_57b.y<0){_57b.h+=_57b.y;_57b.y=0;}if(_57b.x<0){_57b.w+=_57b.x;_57b.x=0;}if(_57b.y+_57b.h>_578){_57b.h=_578-_57b.y;}if(_57b.x+_57b.w>_577){_57b.w=_577-_57b.x;}}var l=_579.x-_57b.x,t=_579.y-Math.max(_57b.y,0),r=l+_579.w-_57b.w,bot=t+_579.h-_57b.h;if(r*l>0){var s=Math[l<0?"max":"min"](l,r);if(rtl&&((isIE==8&&!_574)||isIE>=9)){s=-s;}_579.x+=el.scrollLeft;el.scrollLeft+=s;_579.x-=el.scrollLeft;}if(bot*t>0){_579.y+=el.scrollTop;el.scrollTop+=Math[t<0?"max":"min"](t,bot);_579.y-=el.scrollTop;}el=(el!=_576)&&!_57c&&el.parentNode;}}catch(error){console.error("scrollIntoView: "+error);node.scrollIntoView(false);}};return _570;});},"dojox/charting/axis2d/Default":function(){define("dojox/charting/axis2d/Default",["dojo/_base/lang","dojo/_base/array","dojo/_base/sniff","dojo/_base/declare","dojo/_base/connect","dojo/_base/html","dojo/dom-geometry","./Invisible","../scaler/common","../scaler/linear","./common","dojox/gfx","dojox/lang/utils"],function(lang,arr,has,_57f,_580,html,_581,_582,_583,lin,_584,g,du){var _585=4,_586=45;return _57f("dojox.charting.axis2d.Default",_582,{defaultParams:{vertical:false,fixUpper:"none",fixLower:"none",natural:false,leftBottom:true,includeZero:false,fixed:true,majorLabels:true,minorTicks:true,minorLabels:true,microTicks:false,rotation:0,htmlLabels:true,enableCache:false},optionalParams:{min:0,max:1,from:0,to:1,majorTickStep:4,minorTickStep:2,microTickStep:1,labels:[],labelFunc:null,maxLabelSize:0,maxLabelCharCount:0,trailingSymbol:null,stroke:{},majorTick:{},minorTick:{},microTick:{},tick:{},font:"",fontColor:"",title:"",titleGap:0,titleFont:"",titleFontColor:"",titleOrientation:""},constructor:function(_587,_588){this.opt=lang.clone(this.defaultParams);du.updateWithObject(this.opt,_588);du.updateWithPattern(this.opt,_588,this.optionalParams);if(this.opt.enableCache){this._textFreePool=[];this._lineFreePool=[];this._textUsePool=[];this._lineUsePool=[];}},getOffsets:function(){var s=this.scaler,_589={l:0,r:0,t:0,b:0};if(!s){return _589;}var o=this.opt,_58a=0,a,b,c,d,gl=_583.getNumericLabel,_58b=0,ma=s.major,mi=s.minor,ta=this.chart.theme.axis,_58c=o.font||(ta.majorTick&&ta.majorTick.font)||(ta.tick&&ta.tick.font),_58d=o.titleFont||(ta.tick&&ta.tick.titleFont),_58e=(o.titleGap==0)?0:o.titleGap||(ta.tick&&ta.tick.titleGap)||15,_58f=this.chart.theme.getTick("major",o),_590=this.chart.theme.getTick("minor",o),size=_58c?g.normalizedLength(g.splitFontString(_58c).size):0,_591=_58d?g.normalizedLength(g.splitFontString(_58d).size):0,_592=o.rotation%360,_593=o.leftBottom,cosr=Math.abs(Math.cos(_592*Math.PI/180)),sinr=Math.abs(Math.sin(_592*Math.PI/180));this.trailingSymbol=(o.trailingSymbol===undefined||o.trailingSymbol===null)?this.trailingSymbol:o.trailingSymbol;if(_592<0){_592+=360;}if(size){if(this.labels){_58a=this._groupLabelWidth(this.labels,_58c,o.maxLabelCharCount);}else{_58a=this._groupLabelWidth([gl(ma.start,ma.prec,o),gl(ma.start+ma.count*ma.tick,ma.prec,o),gl(mi.start,mi.prec,o),gl(mi.start+mi.count*mi.tick,mi.prec,o)],_58c,o.maxLabelCharCount);}_58a=o.maxLabelSize?Math.min(o.maxLabelSize,_58a):_58a;if(this.vertical){var side=_593?"l":"r";switch(_592){case 0:case 180:_589[side]=_58a;_589.t=_589.b=size/2;break;case 90:case 270:_589[side]=size;_589.t=_589.b=_58a/2;break;default:if(_592<=_586||(180<_592&&_592<=(180+_586))){_589[side]=size*sinr/2+_58a*cosr;_589[_593?"t":"b"]=size*cosr/2+_58a*sinr;_589[_593?"b":"t"]=size*cosr/2;}else{if(_592>(360-_586)||(180>_592&&_592>(180-_586))){_589[side]=size*sinr/2+_58a*cosr;_589[_593?"b":"t"]=size*cosr/2+_58a*sinr;_589[_593?"t":"b"]=size*cosr/2;}else{if(_592<90||(180<_592&&_592<270)){_589[side]=size*sinr+_58a*cosr;_589[_593?"t":"b"]=size*cosr+_58a*sinr;}else{_589[side]=size*sinr+_58a*cosr;_589[_593?"b":"t"]=size*cosr+_58a*sinr;}}}break;}_589[side]+=_585+Math.max(_58f.length,_590.length)+(o.title?(_591+_58e):0);}else{var side=_593?"b":"t";switch(_592){case 0:case 180:_589[side]=size;_589.l=_589.r=_58a/2;break;case 90:case 270:_589[side]=_58a;_589.l=_589.r=size/2;break;default:if((90-_586)<=_592&&_592<=90||(270-_586)<=_592&&_592<=270){_589[side]=size*sinr/2+_58a*cosr;_589[_593?"r":"l"]=size*cosr/2+_58a*sinr;_589[_593?"l":"r"]=size*cosr/2;}else{if(90<=_592&&_592<=(90+_586)||270<=_592&&_592<=(270+_586)){_589[side]=size*sinr/2+_58a*cosr;_589[_593?"l":"r"]=size*cosr/2+_58a*sinr;_589[_593?"r":"l"]=size*cosr/2;}else{if(_592<_586||(180<_592&&_592<(180-_586))){_589[side]=size*sinr+_58a*cosr;_589[_593?"r":"l"]=size*cosr+_58a*sinr;}else{_589[side]=size*sinr+_58a*cosr;_589[_593?"l":"r"]=size*cosr+_58a*sinr;}}}break;}_589[side]+=_585+Math.max(_58f.length,_590.length)+(o.title?(_591+_58e):0);}}if(_58a){this._cachedLabelWidth=_58a;}return _589;},cleanGroup:function(_594){if(this.opt.enableCache&&this.group){this._lineFreePool=this._lineFreePool.concat(this._lineUsePool);this._lineUsePool=[];this._textFreePool=this._textFreePool.concat(this._textUsePool);this._textUsePool=[];}this.inherited(arguments);},createText:function(_595,_596,x,y,_597,_598,font,_599,_59a){if(!this.opt.enableCache||_595=="html"){return _584.createText[_595](this.chart,_596,x,y,_597,_598,font,_599,_59a);}var text;if(this._textFreePool.length>0){text=this._textFreePool.pop();text.setShape({x:x,y:y,text:_598,align:_597});_596.add(text);}else{text=_584.createText[_595](this.chart,_596,x,y,_597,_598,font,_599,_59a);}this._textUsePool.push(text);return text;},createLine:function(_59b,_59c){var line;if(this.opt.enableCache&&this._lineFreePool.length>0){line=this._lineFreePool.pop();line.setShape(_59c);_59b.add(line);}else{line=_59b.createLine(_59c);}if(this.opt.enableCache){this._lineUsePool.push(line);}return line;},render:function(dim,_59d){if(!this.dirty){return this;}var o=this.opt,ta=this.chart.theme.axis,_59e=o.leftBottom,_59f=o.rotation%360,_5a0,stop,_5a1,_5a2=0,_5a3,_5a4,_5a5,_5a6,_5a7,_5a8,_5a9=o.font||(ta.majorTick&&ta.majorTick.font)||(ta.tick&&ta.tick.font),_5aa=o.titleFont||(ta.tick&&ta.tick.titleFont),_5ab=o.fontColor||(ta.majorTick&&ta.majorTick.fontColor)||(ta.tick&&ta.tick.fontColor)||"black",_5ac=o.titleFontColor||(ta.tick&&ta.tick.titleFontColor)||"black",_5ad=(o.titleGap==0)?0:o.titleGap||(ta.tick&&ta.tick.titleGap)||15,_5ae=o.titleOrientation||(ta.tick&&ta.tick.titleOrientation)||"axis",_5af=this.chart.theme.getTick("major",o),_5b0=this.chart.theme.getTick("minor",o),_5b1=this.chart.theme.getTick("micro",o),_5b2=Math.max(_5af.length,_5b0.length,_5b1.length),_5b3="stroke" in o?o.stroke:ta.stroke,size=_5a9?g.normalizedLength(g.splitFontString(_5a9).size):0,cosr=Math.abs(Math.cos(_59f*Math.PI/180)),sinr=Math.abs(Math.sin(_59f*Math.PI/180)),_5b4=_5aa?g.normalizedLength(g.splitFontString(_5aa).size):0;if(_59f<0){_59f+=360;}if(this.vertical){_5a0={y:dim.height-_59d.b};stop={y:_59d.t};_5a1={y:(dim.height-_59d.b+_59d.t)/2};_5a3=size*sinr+(this._cachedLabelWidth||0)*cosr+_585+Math.max(_5af.length,_5b0.length)+_5b4+_5ad;_5a4={x:0,y:-1};_5a7={x:0,y:0};_5a5={x:1,y:0};_5a6={x:_585,y:0};switch(_59f){case 0:_5a8="end";_5a7.y=size*0.4;break;case 90:_5a8="middle";_5a7.x=-size;break;case 180:_5a8="start";_5a7.y=-size*0.4;break;case 270:_5a8="middle";break;default:if(_59f<_586){_5a8="end";_5a7.y=size*0.4;}else{if(_59f<90){_5a8="end";_5a7.y=size*0.4;}else{if(_59f<(180-_586)){_5a8="start";}else{if(_59f<(180+_586)){_5a8="start";_5a7.y=-size*0.4;}else{if(_59f<270){_5a8="start";_5a7.x=_59e?0:size*0.4;}else{if(_59f<(360-_586)){_5a8="end";_5a7.x=_59e?0:size*0.4;}else{_5a8="end";_5a7.y=size*0.4;}}}}}}}if(_59e){_5a0.x=stop.x=_59d.l;_5a2=(_5ae&&_5ae=="away")?90:270;_5a1.x=_59d.l-_5a3+(_5a2==270?_5b4:0);_5a5.x=-1;_5a6.x=-_5a6.x;}else{_5a0.x=stop.x=dim.width-_59d.r;_5a2=(_5ae&&_5ae=="axis")?90:270;_5a1.x=dim.width-_59d.r+_5a3-(_5a2==270?0:_5b4);switch(_5a8){case "start":_5a8="end";break;case "end":_5a8="start";break;case "middle":_5a7.x+=size;break;}}}else{_5a0={x:_59d.l};stop={x:dim.width-_59d.r};_5a1={x:(dim.width-_59d.r+_59d.l)/2};_5a3=size*cosr+(this._cachedLabelWidth||0)*sinr+_585+Math.max(_5af.length,_5b0.length)+_5b4+_5ad;_5a4={x:1,y:0};_5a7={x:0,y:0};_5a5={x:0,y:1};_5a6={x:0,y:_585};switch(_59f){case 0:_5a8="middle";_5a7.y=size;break;case 90:_5a8="start";_5a7.x=-size*0.4;break;case 180:_5a8="middle";break;case 270:_5a8="end";_5a7.x=size*0.4;break;default:if(_59f<(90-_586)){_5a8="start";_5a7.y=_59e?size:0;}else{if(_59f<(90+_586)){_5a8="start";_5a7.x=-size*0.4;}else{if(_59f<180){_5a8="start";_5a7.y=_59e?0:-size;}else{if(_59f<(270-_586)){_5a8="end";_5a7.y=_59e?0:-size;}else{if(_59f<(270+_586)){_5a8="end";_5a7.y=_59e?size*0.4:0;}else{_5a8="end";_5a7.y=_59e?size:0;}}}}}}if(_59e){_5a0.y=stop.y=dim.height-_59d.b;_5a2=(_5ae&&_5ae=="axis")?180:0;_5a1.y=dim.height-_59d.b+_5a3-(_5a2?_5b4:0);}else{_5a0.y=stop.y=_59d.t;_5a2=(_5ae&&_5ae=="away")?180:0;_5a1.y=_59d.t-_5a3+(_5a2?0:_5b4);_5a5.y=-1;_5a6.y=-_5a6.y;switch(_5a8){case "start":_5a8="end";break;case "end":_5a8="start";break;case "middle":_5a7.y-=size;break;}}}this.cleanGroup();try{var s=this.group,c=this.scaler,t=this.ticks,_5b5,f=lin.getTransformerFromModel(this.scaler),_5b6=(!o.title||!_5a2)&&!_59f&&this.opt.htmlLabels&&!has("ie")&&!has("opera")?"html":"gfx",dx=_5a5.x*_5af.length,dy=_5a5.y*_5af.length;s.createLine({x1:_5a0.x,y1:_5a0.y,x2:stop.x,y2:stop.y}).setStroke(_5b3);if(o.title){var _5b7=_584.createText[_5b6](this.chart,s,_5a1.x,_5a1.y,"middle",o.title,_5aa,_5ac);if(_5b6=="html"){this.htmlElements.push(_5b7);}else{_5b7.setTransform(g.matrix.rotategAt(_5a2,_5a1.x,_5a1.y));}}if(t==null){this.dirty=false;return this;}arr.forEach(t.major,function(tick){var _5b8=f(tick.value),elem,x=_5a0.x+_5a4.x*_5b8,y=_5a0.y+_5a4.y*_5b8;this.createLine(s,{x1:x,y1:y,x2:x+dx,y2:y+dy}).setStroke(_5af);if(tick.label){var _5b9=o.maxLabelCharCount?this.getTextWithLimitCharCount(tick.label,_5a9,o.maxLabelCharCount):{text:tick.label,truncated:false};_5b9=o.maxLabelSize?this.getTextWithLimitLength(_5b9.text,_5a9,o.maxLabelSize,_5b9.truncated):_5b9;elem=this.createText(_5b6,s,x+dx+_5a6.x+(_59f?0:_5a7.x),y+dy+_5a6.y+(_59f?0:_5a7.y),_5a8,_5b9.text,_5a9,_5ab);if(this.chart.truncateBidi&&_5b9.truncated){this.chart.truncateBidi(elem,tick.label,_5b6);}_5b9.truncated&&this.labelTooltip(elem,this.chart,tick.label,_5b9.text,_5a9,_5b6);if(_5b6=="html"){this.htmlElements.push(elem);}else{if(_59f){elem.setTransform([{dx:_5a7.x,dy:_5a7.y},g.matrix.rotategAt(_59f,x+dx+_5a6.x,y+dy+_5a6.y)]);}}}},this);dx=_5a5.x*_5b0.length;dy=_5a5.y*_5b0.length;_5b5=c.minMinorStep<=c.minor.tick*c.bounds.scale;arr.forEach(t.minor,function(tick){var _5ba=f(tick.value),elem,x=_5a0.x+_5a4.x*_5ba,y=_5a0.y+_5a4.y*_5ba;this.createLine(s,{x1:x,y1:y,x2:x+dx,y2:y+dy}).setStroke(_5b0);if(_5b5&&tick.label){var _5bb=o.maxLabelCharCount?this.getTextWithLimitCharCount(tick.label,_5a9,o.maxLabelCharCount):{text:tick.label,truncated:false};_5bb=o.maxLabelSize?this.getTextWithLimitLength(_5bb.text,_5a9,o.maxLabelSize,_5bb.truncated):_5bb;elem=this.createText(_5b6,s,x+dx+_5a6.x+(_59f?0:_5a7.x),y+dy+_5a6.y+(_59f?0:_5a7.y),_5a8,_5bb.text,_5a9,_5ab);if(this.chart.getTextDir&&_5bb.truncated){this.chart.truncateBidi(elem,tick.label,_5b6);}_5bb.truncated&&this.labelTooltip(elem,this.chart,tick.label,_5bb.text,_5a9,_5b6);if(_5b6=="html"){this.htmlElements.push(elem);}else{if(_59f){elem.setTransform([{dx:_5a7.x,dy:_5a7.y},g.matrix.rotategAt(_59f,x+dx+_5a6.x,y+dy+_5a6.y)]);}}}},this);dx=_5a5.x*_5b1.length;dy=_5a5.y*_5b1.length;arr.forEach(t.micro,function(tick){var _5bc=f(tick.value),elem,x=_5a0.x+_5a4.x*_5bc,y=_5a0.y+_5a4.y*_5bc;this.createLine(s,{x1:x,y1:y,x2:x+dx,y2:y+dy}).setStroke(_5b1);},this);}catch(e){}this.dirty=false;return this;},labelTooltip:function(elem,_5bd,_5be,_5bf,font,_5c0){var _5c1=["dijit/Tooltip"];var _5c2={type:"rect"},_5c3=["above","below"],_5c4=g._base._getTextBox(_5bf,{font:font}).w||0,_5c5=font?g.normalizedLength(g.splitFontString(font).size):0;if(_5c0=="html"){lang.mixin(_5c2,html.coords(elem.firstChild,true));_5c2.width=Math.ceil(_5c4);_5c2.height=Math.ceil(_5c5);this._events.push({shape:dojo,handle:_580.connect(elem.firstChild,"onmouseover",this,function(e){require(_5c1,function(_5c6){_5c6.show(_5be,_5c2,_5c3);});})});this._events.push({shape:dojo,handle:_580.connect(elem.firstChild,"onmouseout",this,function(e){require(_5c1,function(_5c7){_5c7.hide(_5c2);});})});}else{var shp=elem.getShape(),lt=html.coords(_5bd.node,true);_5c2=lang.mixin(_5c2,{x:shp.x-_5c4/2,y:shp.y});_5c2.x+=lt.x;_5c2.y+=lt.y;_5c2.x=Math.round(_5c2.x);_5c2.y=Math.round(_5c2.y);_5c2.width=Math.ceil(_5c4);_5c2.height=Math.ceil(_5c5);this._events.push({shape:elem,handle:elem.connect("onmouseenter",this,function(e){require(_5c1,function(_5c8){_5c8.show(_5be,_5c2,_5c3);});})});this._events.push({shape:elem,handle:elem.connect("onmouseleave",this,function(e){require(_5c1,function(_5c9){_5c9.hide(_5c2);});})});}}});});},"dojox/charting/plot2d/ClusteredBars":function(){define("dojox/charting/plot2d/ClusteredBars",["dojo/_base/lang","dojo/_base/array","dojo/_base/declare","./Bars","./common","dojox/lang/functional","dojox/lang/functional/reversed","dojox/lang/utils"],function(lang,arr,_5ca,Bars,dc,df,dfr,du){var _5cb=dfr.lambda("item.purgeGroup()");return _5ca("dojox.charting.plot2d.ClusteredBars",Bars,{render:function(dim,_5cc){if(this.zoom&&!this.isDataDirty()){return this.performZoom(dim,_5cc);}this.resetEvents();this.dirty=this.isDirty();if(this.dirty){arr.forEach(this.series,_5cb);this._eventSeries={};this.cleanGroup();var s=this.group;df.forEachRev(this.series,function(item){item.cleanGroup(s);});}var t=this.chart.theme,f,gap,_5cd,_5ce,ht=this._hScaler.scaler.getTransformerFromModel(this._hScaler),vt=this._vScaler.scaler.getTransformerFromModel(this._vScaler),_5cf=Math.max(0,this._hScaler.bounds.lower),_5d0=ht(_5cf),_5d1=this.events();f=dc.calculateBarSize(this._vScaler.bounds.scale,this.opt,this.series.length);gap=f.gap;_5cd=_5ce=f.size;for(var i=this.series.length-1;i>=0;--i){var run=this.series[i],_5d2=_5ce*(this.series.length-i-1);if(!this.dirty&&!run.dirty){t.skip();this._reconnectEvents(run.name);continue;}run.cleanGroup();var _5d3=t.next("bar",[this.opt,run]),s=run.group,_5d4=new Array(run.data.length);for(var j=0;j<run.data.length;++j){var _5d5=run.data[j];if(_5d5!==null){var v=typeof _5d5=="number"?_5d5:_5d5.y,hv=ht(v),_5d6=hv-_5d0,w=Math.abs(_5d6),_5d7=typeof _5d5!="number"?t.addMixin(_5d3,"bar",_5d5,true):t.post(_5d3,"bar");if(w>=0&&_5cd>=1){var rect={x:_5cc.l+(v<_5cf?hv:_5d0),y:dim.height-_5cc.b-vt(j+1.5)+gap+_5d2,width:w,height:_5cd};var _5d8=this._plotFill(_5d7.series.fill,dim,_5cc);_5d8=this._shapeFill(_5d8,rect);var _5d9=s.createRect(rect).setFill(_5d8).setStroke(_5d7.series.stroke);run.dyn.fill=_5d9.getFill();run.dyn.stroke=_5d9.getStroke();if(_5d1){var o={element:"bar",index:j,run:run,shape:_5d9,x:v,y:j+1.5};this._connectEvents(o);_5d4[j]=o;}if(this.animate){this._animateBar(_5d9,_5cc.l+_5d0,-_5d6);}}}}this._eventSeries[run.name]=_5d4;run.dirty=false;}this.dirty=false;return this;}});});},"dojox/charting/action2d/MoveSlice":function(){define("dojox/charting/action2d/MoveSlice",["dojo/_base/connect","dojo/_base/declare","./PlotAction","dojo/fx/easing","dojox/gfx/matrix","dojox/gfx/fx","dojox/lang/functional","dojox/lang/functional/scan","dojox/lang/functional/fold"],function(hub,_5da,_5db,dfe,m,gf,df,dfs,dff){var _5dc=1.05,_5dd=7;return _5da("dojox.charting.action2d.MoveSlice",_5db,{defaultParams:{duration:400,easing:dfe.backOut,scale:_5dc,shift:_5dd},optionalParams:{},constructor:function(_5de,plot,_5df){if(!_5df){_5df={};}this.scale=typeof _5df.scale=="number"?_5df.scale:_5dc;this.shift=typeof _5df.shift=="number"?_5df.shift:_5dd;this.connect();},process:function(o){if(!o.shape||o.element!="slice"||!(o.type in this.overOutEvents)){return;}if(!this.angles){var _5e0=m._degToRad(o.plot.opt.startAngle);if(typeof o.run.data[0]=="number"){this.angles=df.map(df.scanl(o.run.data,"+",_5e0),"* 2 * Math.PI / this",df.foldl(o.run.data,"+",0));}else{this.angles=df.map(df.scanl(o.run.data,"a + b.y",_5e0),"* 2 * Math.PI / this",df.foldl(o.run.data,"a + b.y",0));}}var _5e1=o.index,anim,_5e2,_5e3,_5e4,_5e5,_5e6=(this.angles[_5e1]+this.angles[_5e1+1])/2,_5e7=m.rotateAt(-_5e6,o.cx,o.cy),_5e8=m.rotateAt(_5e6,o.cx,o.cy);anim=this.anim[_5e1];if(anim){anim.action.stop(true);}else{this.anim[_5e1]=anim={};}if(o.type=="onmouseover"){_5e4=0;_5e5=this.shift;_5e2=1;_5e3=this.scale;}else{_5e4=this.shift;_5e5=0;_5e2=this.scale;_5e3=1;}anim.action=gf.animateTransform({shape:o.shape,duration:this.duration,easing:this.easing,transform:[_5e8,{name:"translate",start:[_5e4,0],end:[_5e5,0]},{name:"scaleAt",start:[_5e2,o.cx,o.cy],end:[_5e3,o.cx,o.cy]},_5e7]});if(o.type=="onmouseout"){hub.connect(anim.action,"onEnd",this,function(){delete this.anim[_5e1];});}anim.action.play();},reset:function(){delete this.angles;}});});},"dojo/colors":function(){define(["./_base/kernel","./_base/lang","./_base/Color","./_base/array"],function(dojo,lang,_5e9,_5ea){var _5eb=lang.getObject("dojo.colors",true);var _5ec=function(m1,m2,h){if(h<0){++h;}if(h>1){--h;}var h6=6*h;if(h6<1){return m1+(m2-m1)*h6;}if(2*h<1){return m2;}if(3*h<2){return m1+(m2-m1)*(2/3-h)*6;}return m1;};dojo.colorFromRgb=_5e9.fromRgb=function(_5ed,obj){var m=_5ed.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);if(m){var c=m[2].split(/\s*,\s*/),l=c.length,t=m[1],a;if((t=="rgb"&&l==3)||(t=="rgba"&&l==4)){var r=c[0];if(r.charAt(r.length-1)=="%"){a=_5ea.map(c,function(x){return parseFloat(x)*2.56;});if(l==4){a[3]=c[3];}return _5e9.fromArray(a,obj);}return _5e9.fromArray(c,obj);}if((t=="hsl"&&l==3)||(t=="hsla"&&l==4)){var H=((parseFloat(c[0])%360)+360)%360/360,S=parseFloat(c[1])/100,L=parseFloat(c[2])/100,m2=L<=0.5?L*(S+1):L+S-L*S,m1=2*L-m2;a=[_5ec(m1,m2,H+1/3)*256,_5ec(m1,m2,H)*256,_5ec(m1,m2,H-1/3)*256,1];if(l==4){a[3]=c[3];}return _5e9.fromArray(a,obj);}}return null;};var _5ee=function(c,low,high){c=Number(c);return isNaN(c)?high:c<low?low:c>high?high:c;};_5e9.prototype.sanitize=function(){var t=this;t.r=Math.round(_5ee(t.r,0,255));t.g=Math.round(_5ee(t.g,0,255));t.b=Math.round(_5ee(t.b,0,255));t.a=_5ee(t.a,0,1);return this;};_5eb.makeGrey=_5e9.makeGrey=function(g,a){return _5e9.fromArray([g,g,g,a]);};lang.mixin(_5e9.named,{"aliceblue":[240,248,255],"antiquewhite":[250,235,215],"aquamarine":[127,255,212],"azure":[240,255,255],"beige":[245,245,220],"bisque":[255,228,196],"blanchedalmond":[255,235,205],"blueviolet":[138,43,226],"brown":[165,42,42],"burlywood":[222,184,135],"cadetblue":[95,158,160],"chartreuse":[127,255,0],"chocolate":[210,105,30],"coral":[255,127,80],"cornflowerblue":[100,149,237],"cornsilk":[255,248,220],"crimson":[220,20,60],"cyan":[0,255,255],"darkblue":[0,0,139],"darkcyan":[0,139,139],"darkgoldenrod":[184,134,11],"darkgray":[169,169,169],"darkgreen":[0,100,0],"darkgrey":[169,169,169],"darkkhaki":[189,183,107],"darkmagenta":[139,0,139],"darkolivegreen":[85,107,47],"darkorange":[255,140,0],"darkorchid":[153,50,204],"darkred":[139,0,0],"darksalmon":[233,150,122],"darkseagreen":[143,188,143],"darkslateblue":[72,61,139],"darkslategray":[47,79,79],"darkslategrey":[47,79,79],"darkturquoise":[0,206,209],"darkviolet":[148,0,211],"deeppink":[255,20,147],"deepskyblue":[0,191,255],"dimgray":[105,105,105],"dimgrey":[105,105,105],"dodgerblue":[30,144,255],"firebrick":[178,34,34],"floralwhite":[255,250,240],"forestgreen":[34,139,34],"gainsboro":[220,220,220],"ghostwhite":[248,248,255],"gold":[255,215,0],"goldenrod":[218,165,32],"greenyellow":[173,255,47],"grey":[128,128,128],"honeydew":[240,255,240],"hotpink":[255,105,180],"indianred":[205,92,92],"indigo":[75,0,130],"ivory":[255,255,240],"khaki":[240,230,140],"lavender":[230,230,250],"lavenderblush":[255,240,245],"lawngreen":[124,252,0],"lemonchiffon":[255,250,205],"lightblue":[173,216,230],"lightcoral":[240,128,128],"lightcyan":[224,255,255],"lightgoldenrodyellow":[250,250,210],"lightgray":[211,211,211],"lightgreen":[144,238,144],"lightgrey":[211,211,211],"lightpink":[255,182,193],"lightsalmon":[255,160,122],"lightseagreen":[32,178,170],"lightskyblue":[135,206,250],"lightslategray":[119,136,153],"lightslategrey":[119,136,153],"lightsteelblue":[176,196,222],"lightyellow":[255,255,224],"limegreen":[50,205,50],"linen":[250,240,230],"magenta":[255,0,255],"mediumaquamarine":[102,205,170],"mediumblue":[0,0,205],"mediumorchid":[186,85,211],"mediumpurple":[147,112,219],"mediumseagreen":[60,179,113],"mediumslateblue":[123,104,238],"mediumspringgreen":[0,250,154],"mediumturquoise":[72,209,204],"mediumvioletred":[199,21,133],"midnightblue":[25,25,112],"mintcream":[245,255,250],"mistyrose":[255,228,225],"moccasin":[255,228,181],"navajowhite":[255,222,173],"oldlace":[253,245,230],"olivedrab":[107,142,35],"orange":[255,165,0],"orangered":[255,69,0],"orchid":[218,112,214],"palegoldenrod":[238,232,170],"palegreen":[152,251,152],"paleturquoise":[175,238,238],"palevioletred":[219,112,147],"papayawhip":[255,239,213],"peachpuff":[255,218,185],"peru":[205,133,63],"pink":[255,192,203],"plum":[221,160,221],"powderblue":[176,224,230],"rosybrown":[188,143,143],"royalblue":[65,105,225],"saddlebrown":[139,69,19],"salmon":[250,128,114],"sandybrown":[244,164,96],"seagreen":[46,139,87],"seashell":[255,245,238],"sienna":[160,82,45],"skyblue":[135,206,235],"slateblue":[106,90,205],"slategray":[112,128,144],"slategrey":[112,128,144],"snow":[255,250,250],"springgreen":[0,255,127],"steelblue":[70,130,180],"tan":[210,180,140],"thistle":[216,191,216],"tomato":[255,99,71],"turquoise":[64,224,208],"violet":[238,130,238],"wheat":[245,222,179],"whitesmoke":[245,245,245],"yellowgreen":[154,205,50]});return _5e9;});},"dijit/Tooltip":function(){require({cache:{"url:dijit/templates/Tooltip.html":"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n></div>\n"}});define("dijit/Tooltip",["dojo/_base/array","dojo/_base/declare","dojo/_base/fx","dojo/dom","dojo/dom-class","dojo/dom-geometry","dojo/dom-style","dojo/_base/lang","dojo/_base/sniff","dojo/_base/window","./_base/manager","./place","./_Widget","./_TemplatedMixin","./BackgroundIframe","dojo/text!./templates/Tooltip.html","."],function(_5ef,_5f0,fx,dom,_5f1,_5f2,_5f3,lang,has,win,_5f4,_5f5,_5f6,_5f7,_5f8,_5f9,_5fa){var _5fb=_5f0("dijit._MasterTooltip",[_5f6,_5f7],{duration:_5f4.defaultDuration,templateString:_5f9,postCreate:function(){win.body().appendChild(this.domNode);this.bgIframe=new _5f8(this.domNode);this.fadeIn=fx.fadeIn({node:this.domNode,duration:this.duration,onEnd:lang.hitch(this,"_onShow")});this.fadeOut=fx.fadeOut({node:this.domNode,duration:this.duration,onEnd:lang.hitch(this,"_onHide")});},show:function(_5fc,_5fd,_5fe,rtl,_5ff){if(this.aroundNode&&this.aroundNode===_5fd&&this.containerNode.innerHTML==_5fc){return;}this.domNode.width="auto";if(this.fadeOut.status()=="playing"){this._onDeck=arguments;return;}this.containerNode.innerHTML=_5fc;this.set("textDir",_5ff);this.containerNode.align=rtl?"right":"left";var pos=_5f5.around(this.domNode,_5fd,_5fe&&_5fe.length?_5fe:_600.defaultPosition,!rtl,lang.hitch(this,"orient"));var _601=pos.aroundNodePos;if(pos.corner.charAt(0)=="M"&&pos.aroundCorner.charAt(0)=="M"){this.connectorNode.style.top=_601.y+((_601.h-this.connectorNode.offsetHeight)>>1)-pos.y+"px";this.connectorNode.style.left="";}else{if(pos.corner.charAt(1)=="M"&&pos.aroundCorner.charAt(1)=="M"){this.connectorNode.style.left=_601.x+((_601.w-this.connectorNode.offsetWidth)>>1)-pos.x+"px";}}_5f3.set(this.domNode,"opacity",0);this.fadeIn.play();this.isShowingNow=true;this.aroundNode=_5fd;},orient:function(node,_602,_603,_604,_605){this.connectorNode.style.top="";var _606=_604.w-this.connectorNode.offsetWidth;node.className="dijitTooltip "+{"MR-ML":"dijitTooltipRight","ML-MR":"dijitTooltipLeft","TM-BM":"dijitTooltipAbove","BM-TM":"dijitTooltipBelow","BL-TL":"dijitTooltipBelow dijitTooltipABLeft","TL-BL":"dijitTooltipAbove dijitTooltipABLeft","BR-TR":"dijitTooltipBelow dijitTooltipABRight","TR-BR":"dijitTooltipAbove dijitTooltipABRight","BR-BL":"dijitTooltipRight","BL-BR":"dijitTooltipLeft"}[_602+"-"+_603];this.domNode.style.width="auto";var size=_5f2.getContentBox(this.domNode);var _607=Math.min((Math.max(_606,1)),size.w);var _608=_607<size.w;this.domNode.style.width=_607+"px";if(_608){this.containerNode.style.overflow="auto";var _609=this.containerNode.scrollWidth;this.containerNode.style.overflow="visible";if(_609>_607){_609=_609+_5f3.get(this.domNode,"paddingLeft")+_5f3.get(this.domNode,"paddingRight");this.domNode.style.width=_609+"px";}}if(_603.charAt(0)=="B"&&_602.charAt(0)=="B"){var mb=_5f2.getMarginBox(node);var _60a=this.connectorNode.offsetHeight;if(mb.h>_604.h){var _60b=_604.h-((_605.h+_60a)>>1);this.connectorNode.style.top=_60b+"px";this.connectorNode.style.bottom="";}else{this.connectorNode.style.bottom=Math.min(Math.max(_605.h/2-_60a/2,0),mb.h-_60a)+"px";this.connectorNode.style.top="";}}else{this.connectorNode.style.top="";this.connectorNode.style.bottom="";}return Math.max(0,size.w-_606);},_onShow:function(){if(has("ie")){this.domNode.style.filter="";}},hide:function(_60c){if(this._onDeck&&this._onDeck[1]==_60c){this._onDeck=null;}else{if(this.aroundNode===_60c){this.fadeIn.stop();this.isShowingNow=false;this.aroundNode=null;this.fadeOut.play();}else{}}},_onHide:function(){this.domNode.style.cssText="";this.containerNode.innerHTML="";if(this._onDeck){this.show.apply(this,this._onDeck);this._onDeck=null;}},_setAutoTextDir:function(node){this.applyTextDir(node,has("ie")?node.outerText:node.textContent);_5ef.forEach(node.children,function(_60d){this._setAutoTextDir(_60d);},this);},_setTextDirAttr:function(_60e){this._set("textDir",typeof _60e!="undefined"?_60e:"");if(_60e=="auto"){this._setAutoTextDir(this.containerNode);}else{this.containerNode.dir=this.textDir;}}});_5fa.showTooltip=function(_60f,_610,_611,rtl,_612){if(!_600._masterTT){_5fa._masterTT=_600._masterTT=new _5fb();}return _600._masterTT.show(_60f,_610,_611,rtl,_612);};_5fa.hideTooltip=function(_613){return _600._masterTT&&_600._masterTT.hide(_613);};var _600=_5f0("dijit.Tooltip",_5f6,{label:"",showDelay:400,connectId:[],position:[],_setConnectIdAttr:function(_614){_5ef.forEach(this._connections||[],function(_615){_5ef.forEach(_615,lang.hitch(this,"disconnect"));},this);this._connectIds=_5ef.filter(lang.isArrayLike(_614)?_614:(_614?[_614]:[]),function(id){return dom.byId(id);});this._connections=_5ef.map(this._connectIds,function(id){var node=dom.byId(id);return [this.connect(node,"onmouseenter","_onHover"),this.connect(node,"onmouseleave","_onUnHover"),this.connect(node,"onfocus","_onHover"),this.connect(node,"onblur","_onUnHover")];},this);this._set("connectId",_614);},addTarget:function(node){var id=node.id||node;if(_5ef.indexOf(this._connectIds,id)==-1){this.set("connectId",this._connectIds.concat(id));}},removeTarget:function(node){var id=node.id||node,idx=_5ef.indexOf(this._connectIds,id);if(idx>=0){this._connectIds.splice(idx,1);this.set("connectId",this._connectIds);}},buildRendering:function(){this.inherited(arguments);_5f1.add(this.domNode,"dijitTooltipData");},startup:function(){this.inherited(arguments);var ids=this.connectId;_5ef.forEach(lang.isArrayLike(ids)?ids:[ids],this.addTarget,this);},_onHover:function(e){if(!this._showTimer){var _616=e.target;this._showTimer=setTimeout(lang.hitch(this,function(){this.open(_616);}),this.showDelay);}},_onUnHover:function(){if(this._focus){return;}if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}this.close();},open:function(_617){if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}_600.show(this.label||this.domNode.innerHTML,_617,this.position,!this.isLeftToRight(),this.textDir);this._connectNode=_617;this.onShow(_617,this.position);},close:function(){if(this._connectNode){_600.hide(this._connectNode);delete this._connectNode;this.onHide();}if(this._showTimer){clearTimeout(this._showTimer);delete this._showTimer;}},onShow:function(){},onHide:function(){},uninitialize:function(){this.close();this.inherited(arguments);}});_600._MasterTooltip=_5fb;_600.show=_5fa.showTooltip;_600.hide=_5fa.hideTooltip;_600.defaultPosition=["after-centered","before-centered"];return _600;});},"dojox/charting/Element":function(){define("dojox/charting/Element",["dojo/_base/lang","dojo/_base/array","dojo/dom-construct","dojo/_base/declare","dojox/gfx","dojox/gfx/utils","dojox/gfx/shape"],function(lang,arr,_618,_619,gfx,_61a,_61b){return _619("dojox.charting.Element",null,{chart:null,group:null,htmlElements:null,dirty:true,constructor:function(_61c){this.chart=_61c;this.group=null;this.htmlElements=[];this.dirty=true;this.trailingSymbol="...";this._events=[];},createGroup:function(_61d){if(!_61d){_61d=this.chart.surface;}if(!this.group){this.group=_61d.createGroup();}return this;},purgeGroup:function(){this.destroyHtmlElements();if(this.group){_61a.forEach(this.group,function(_61e){_61b.dispose(_61e);});this.group.clear();this.group.removeShape();this.group=null;}this.dirty=true;if(this._events.length){arr.forEach(this._events,function(item){item.shape.disconnect(item.handle);});this._events=[];}return this;},cleanGroup:function(_61f){this.destroyHtmlElements();if(!_61f){_61f=this.chart.surface;}if(this.group){this.group.clear();}else{this.group=_61f.createGroup();}this.dirty=true;return this;},destroyHtmlElements:function(){if(this.htmlElements.length){arr.forEach(this.htmlElements,_618.destroy);this.htmlElements=[];}},destroy:function(){this.purgeGroup();},getTextWidth:function(s,font){return gfx._base._getTextBox(s,{font:font}).w||0;},getTextWithLimitLength:function(s,font,_620,_621){if(!s||s.length<=0){return {text:"",truncated:_621||false};}if(!_620||_620<=0){return {text:s,truncated:_621||false};}var _622=2,_623=0.618,_624=s.substring(0,1)+this.trailingSymbol,_625=this.getTextWidth(_624,font);if(_620<=_625){return {text:_624,truncated:true};}var _626=this.getTextWidth(s,font);if(_626<=_620){return {text:s,truncated:_621||false};}else{var _627=0,end=s.length;while(_627<end){if(end-_627<=_622){while(this.getTextWidth(s.substring(0,_627)+this.trailingSymbol,font)>_620){_627-=1;}return {text:(s.substring(0,_627)+this.trailingSymbol),truncated:true};}var _628=_627+Math.round((end-_627)*_623),_629=this.getTextWidth(s.substring(0,_628),font);if(_629<_620){_627=_628;end=end;}else{_627=_627;end=_628;}}}},getTextWithLimitCharCount:function(s,font,_62a,_62b){if(!s||s.length<=0){return {text:"",truncated:_62b||false};}if(!_62a||_62a<=0||s.length<=_62a){return {text:s,truncated:_62b||false};}return {text:s.substring(0,_62a)+this.trailingSymbol,truncated:true};},_plotFill:function(fill,dim,_62c){if(!fill||!fill.type||!fill.space){return fill;}var _62d=fill.space;switch(fill.type){case "linear":if(_62d==="plot"||_62d==="shapeX"||_62d==="shapeY"){fill=gfx.makeParameters(gfx.defaultLinearGradient,fill);fill.space=_62d;if(_62d==="plot"||_62d==="shapeX"){var span=dim.height-_62c.t-_62c.b;fill.y1=_62c.t+span*fill.y1/100;fill.y2=_62c.t+span*fill.y2/100;}if(_62d==="plot"||_62d==="shapeY"){var span=dim.width-_62c.l-_62c.r;fill.x1=_62c.l+span*fill.x1/100;fill.x2=_62c.l+span*fill.x2/100;}}break;case "radial":if(_62d==="plot"){fill=gfx.makeParameters(gfx.defaultRadialGradient,fill);fill.space=_62d;var _62e=dim.width-_62c.l-_62c.r,_62f=dim.height-_62c.t-_62c.b;fill.cx=_62c.l+_62e*fill.cx/100;fill.cy=_62c.t+_62f*fill.cy/100;fill.r=fill.r*Math.sqrt(_62e*_62e+_62f*_62f)/200;}break;case "pattern":if(_62d==="plot"||_62d==="shapeX"||_62d==="shapeY"){fill=gfx.makeParameters(gfx.defaultPattern,fill);fill.space=_62d;if(_62d==="plot"||_62d==="shapeX"){var span=dim.height-_62c.t-_62c.b;fill.y=_62c.t+span*fill.y/100;fill.height=span*fill.height/100;}if(_62d==="plot"||_62d==="shapeY"){var span=dim.width-_62c.l-_62c.r;fill.x=_62c.l+span*fill.x/100;fill.width=span*fill.width/100;}}break;}return fill;},_shapeFill:function(fill,bbox){if(!fill||!fill.space){return fill;}var _630=fill.space;switch(fill.type){case "linear":if(_630==="shape"||_630==="shapeX"||_630==="shapeY"){fill=gfx.makeParameters(gfx.defaultLinearGradient,fill);fill.space=_630;if(_630==="shape"||_630==="shapeX"){var span=bbox.width;fill.x1=bbox.x+span*fill.x1/100;fill.x2=bbox.x+span*fill.x2/100;}if(_630==="shape"||_630==="shapeY"){var span=bbox.height;fill.y1=bbox.y+span*fill.y1/100;fill.y2=bbox.y+span*fill.y2/100;}}break;case "radial":if(_630==="shape"){fill=gfx.makeParameters(gfx.defaultRadialGradient,fill);fill.space=_630;fill.cx=bbox.x+bbox.width/2;fill.cy=bbox.y+bbox.height/2;fill.r=fill.r*bbox.width/200;}break;case "pattern":if(_630==="shape"||_630==="shapeX"||_630==="shapeY"){fill=gfx.makeParameters(gfx.defaultPattern,fill);fill.space=_630;if(_630==="shape"||_630==="shapeX"){var span=bbox.width;fill.x=bbox.x+span*fill.x/100;fill.width=span*fill.width/100;}if(_630==="shape"||_630==="shapeY"){var span=bbox.height;fill.y=bbox.y+span*fill.y/100;fill.height=span*fill.height/100;}}break;}return fill;},_pseudoRadialFill:function(fill,_631,_632,_633,end){if(!fill||fill.type!=="radial"||fill.space!=="shape"){return fill;}var _634=fill.space;fill=gfx.makeParameters(gfx.defaultRadialGradient,fill);fill.space=_634;if(arguments.length<4){fill.cx=_631.x;fill.cy=_631.y;fill.r=fill.r*_632/100;return fill;}var _635=arguments.length<5?_633:(end+_633)/2;return {type:"linear",x1:_631.x,y1:_631.y,x2:_631.x+fill.r*_632*Math.cos(_635)/100,y2:_631.y+fill.r*_632*Math.sin(_635)/100,colors:fill.colors};return fill;}});});},"dijit/_WidgetBase":function(){define("dijit/_WidgetBase",["require","dojo/_base/array","dojo/aspect","dojo/_base/config","dojo/_base/connect","dojo/_base/declare","dojo/dom","dojo/dom-attr","dojo/dom-class","dojo/dom-construct","dojo/dom-geometry","dojo/dom-style","dojo/_base/kernel","dojo/_base/lang","dojo/on","dojo/ready","dojo/Stateful","dojo/topic","dojo/_base/window","./registry"],function(_636,_637,_638,_639,_63a,_63b,dom,_63c,_63d,_63e,_63f,_640,_641,lang,on,_642,_643,_644,win,_645){if(!_641.isAsync){_642(0,function(){var _646=["dijit/_base/manager"];_636(_646);});}var _647={};function _648(obj){var ret={};for(var attr in obj){ret[attr.toLowerCase()]=true;}return ret;};function _649(attr){return function(val){_63c[val?"set":"remove"](this.domNode,attr,val);this._set(attr,val);};};return _63b("dijit._WidgetBase",_643,{id:"",_setIdAttr:"domNode",lang:"",_setLangAttr:_649("lang"),dir:"",_setDirAttr:_649("dir"),textDir:"","class":"",_setClassAttr:{node:"domNode",type:"class"},style:"",title:"",tooltip:"",baseClass:"",srcNodeRef:null,domNode:null,containerNode:null,attributeMap:{},_blankGif:_639.blankGif||_636.toUrl("dojo/resources/blank.gif"),postscript:function(_64a,_64b){this.create(_64a,_64b);},create:function(_64c,_64d){this.srcNodeRef=dom.byId(_64d);this._connects=[];this._supportingWidgets=[];if(this.srcNodeRef&&(typeof this.srcNodeRef.id=="string")){this.id=this.srcNodeRef.id;}if(_64c){this.params=_64c;lang.mixin(this,_64c);}this.postMixInProperties();if(!this.id){this.id=_645.getUniqueId(this.declaredClass.replace(/\./g,"_"));}_645.add(this);this.buildRendering();if(this.domNode){this._applyAttributes();var _64e=this.srcNodeRef;if(_64e&&_64e.parentNode&&this.domNode!==_64e){_64e.parentNode.replaceChild(this.domNode,_64e);}}if(this.domNode){this.domNode.setAttribute("widgetId",this.id);}this.postCreate();if(this.srcNodeRef&&!this.srcNodeRef.parentNode){delete this.srcNodeRef;}this._created=true;},_applyAttributes:function(){var ctor=this.constructor,list=ctor._setterAttrs;if(!list){list=(ctor._setterAttrs=[]);for(var attr in this.attributeMap){list.push(attr);}var _64f=ctor.prototype;for(var _650 in _64f){if(_650 in this.attributeMap){continue;}var _651="_set"+_650.replace(/^[a-z]|-[a-zA-Z]/g,function(c){return c.charAt(c.length-1).toUpperCase();})+"Attr";if(_651 in _64f){list.push(_650);}}}_637.forEach(list,function(attr){if(this.params&&attr in this.params){}else{if(this[attr]){this.set(attr,this[attr]);}}},this);for(var _652 in this.params){this.set(_652,this[_652]);}},postMixInProperties:function(){},buildRendering:function(){if(!this.domNode){this.domNode=this.srcNodeRef||_63e.create("div");}if(this.baseClass){var _653=this.baseClass.split(" ");if(!this.isLeftToRight()){_653=_653.concat(_637.map(_653,function(name){return name+"Rtl";}));}_63d.add(this.domNode,_653);}},postCreate:function(){},startup:function(){if(this._started){return;}this._started=true;_637.forEach(this.getChildren(),function(obj){if(!obj._started&&!obj._destroyed&&lang.isFunction(obj.startup)){obj.startup();obj._started=true;}});},destroyRecursive:function(_654){this._beingDestroyed=true;this.destroyDescendants(_654);this.destroy(_654);},destroy:function(_655){this._beingDestroyed=true;this.uninitialize();var c;while(c=this._connects.pop()){c.remove();}var w;while(w=this._supportingWidgets.pop()){if(w.destroyRecursive){w.destroyRecursive();}else{if(w.destroy){w.destroy();}}}this.destroyRendering(_655);_645.remove(this.id);this._destroyed=true;},destroyRendering:function(_656){if(this.bgIframe){this.bgIframe.destroy(_656);delete this.bgIframe;}if(this.domNode){if(_656){_63c.remove(this.domNode,"widgetId");}else{_63e.destroy(this.domNode);}delete this.domNode;}if(this.srcNodeRef){if(!_656){_63e.destroy(this.srcNodeRef);}delete this.srcNodeRef;}},destroyDescendants:function(_657){_637.forEach(this.getChildren(),function(_658){if(_658.destroyRecursive){_658.destroyRecursive(_657);}});},uninitialize:function(){return false;},_setStyleAttr:function(_659){var _65a=this.domNode;if(lang.isObject(_659)){_640.set(_65a,_659);}else{if(_65a.style.cssText){_65a.style.cssText+="; "+_659;}else{_65a.style.cssText=_659;}}this._set("style",_659);},_attrToDom:function(attr,_65b,_65c){_65c=arguments.length>=3?_65c:this.attributeMap[attr];_637.forEach(lang.isArray(_65c)?_65c:[_65c],function(_65d){var _65e=this[_65d.node||_65d||"domNode"];var type=_65d.type||"attribute";switch(type){case "attribute":if(lang.isFunction(_65b)){_65b=lang.hitch(this,_65b);}var _65f=_65d.attribute?_65d.attribute:(/^on[A-Z][a-zA-Z]*$/.test(attr)?attr.toLowerCase():attr);_63c.set(_65e,_65f,_65b);break;case "innerText":_65e.innerHTML="";_65e.appendChild(win.doc.createTextNode(_65b));break;case "innerHTML":_65e.innerHTML=_65b;break;case "class":_63d.replace(_65e,_65b,this[attr]);break;}},this);},get:function(name){var _660=this._getAttrNames(name);return this[_660.g]?this[_660.g]():this[name];},set:function(name,_661){if(typeof name==="object"){for(var x in name){this.set(x,name[x]);}return this;}var _662=this._getAttrNames(name),_663=this[_662.s];if(lang.isFunction(_663)){var _664=_663.apply(this,Array.prototype.slice.call(arguments,1));}else{var _665=this.focusNode&&!lang.isFunction(this.focusNode)?"focusNode":"domNode",tag=this[_665].tagName,_666=_647[tag]||(_647[tag]=_648(this[_665])),map=name in this.attributeMap?this.attributeMap[name]:_662.s in this?this[_662.s]:((_662.l in _666&&typeof _661!="function")||/^aria-|^data-|^role$/.test(name))?_665:null;if(map!=null){this._attrToDom(name,_661,map);}this._set(name,_661);}return _664||this;},_attrPairNames:{},_getAttrNames:function(name){var apn=this._attrPairNames;if(apn[name]){return apn[name];}var uc=name.replace(/^[a-z]|-[a-zA-Z]/g,function(c){return c.charAt(c.length-1).toUpperCase();});return (apn[name]={n:name+"Node",s:"_set"+uc+"Attr",g:"_get"+uc+"Attr",l:uc.toLowerCase()});},_set:function(name,_667){var _668=this[name];this[name]=_667;if(this._watchCallbacks&&this._created&&_667!==_668){this._watchCallbacks(name,_668,_667);}},on:function(type,func){return _638.after(this,this._onMap(type),func,true);},_onMap:function(type){var ctor=this.constructor,map=ctor._onMap;if(!map){map=(ctor._onMap={});for(var attr in ctor.prototype){if(/^on/.test(attr)){map[attr.replace(/^on/,"").toLowerCase()]=attr;}}}return map[type.toLowerCase()];},toString:function(){return "[Widget "+this.declaredClass+", "+(this.id||"NO ID")+"]";},getChildren:function(){return this.containerNode?_645.findWidgets(this.containerNode):[];},getParent:function(){return _645.getEnclosingWidget(this.domNode.parentNode);},connect:function(obj,_669,_66a){var _66b=_63a.connect(obj,_669,this,_66a);this._connects.push(_66b);return _66b;},disconnect:function(_66c){var i=_637.indexOf(this._connects,_66c);if(i!=-1){_66c.remove();this._connects.splice(i,1);}},subscribe:function(t,_66d){var _66e=_644.subscribe(t,lang.hitch(this,_66d));this._connects.push(_66e);return _66e;},unsubscribe:function(_66f){this.disconnect(_66f);},isLeftToRight:function(){return this.dir?(this.dir=="ltr"):_63f.isBodyLtr();},isFocusable:function(){return this.focus&&(_640.get(this.domNode,"display")!="none");},placeAt:function(_670,_671){if(_670.declaredClass&&_670.addChild){_670.addChild(this,_671);}else{_63e.place(this.domNode,_670,_671);}return this;},getTextDir:function(text,_672){return _672;},applyTextDir:function(){}});});}}});require(["dojo/i18n"],function(i18n){i18n._preloadLocalizations("dojox/charting/widget/nls/Chart2D",[]);});define("dojox/charting/widget/Chart2D",["dojo/_base/kernel","./Chart","../Chart2D","../action2d/Highlight","../action2d/Magnify","../action2d/MoveSlice","../action2d/Shake","../action2d/Tooltip"],function(dojo,_673){dojo.deprecated("dojox.charting.widget.Chart2D","Use dojo.charting.widget.Chart instead and require all other components explicitly","2.0");return dojox.charting.widget.Chart2D=_673;});
\ No newline at end of file diff --git a/js/dojo-1.7.2/dojox/charting/widget/Chart2D.js.uncompressed.js b/js/dojo-1.7.2/dojox/charting/widget/Chart2D.js.uncompressed.js new file mode 100644 index 0000000..7510f20 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/widget/Chart2D.js.uncompressed.js @@ -0,0 +1,19339 @@ +/* + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. + Available via Academic Free License >= 2.1 OR the modified BSD license. + see: http://dojotoolkit.org/license for details +*/ + +/* + This is an optimized version of Dojo, built for deployment and not for + development. To get sources and documentation, please visit: + + http://dojotoolkit.org +*/ + +//>>built +require({cache:{ +'dojox/charting/plot2d/_PlotEvents':function(){ +define("dojox/charting/plot2d/_PlotEvents", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/_base/connect"], + function(lang, arr, declare, hub){ + + return declare("dojox.charting.plot2d._PlotEvents", null, { + constructor: function(){ + this._shapeEvents = []; + this._eventSeries = {}; + }, + destroy: function(){ + // summary: + // Destroy any internal elements and event handlers. + this.resetEvents(); + this.inherited(arguments); + }, + plotEvent: function(o){ + // summary: + // Stub function for use by specific plots. + // o: Object + // An object intended to represent event parameters. + }, + raiseEvent: function(o){ + // summary: + // Raises events in predefined order + // o: Object + // An object intended to represent event parameters. + this.plotEvent(o); + var t = lang.delegate(o); + t.originalEvent = o.type; + t.originalPlot = o.plot; + t.type = "onindirect"; + arr.forEach(this.chart.stack, function(plot){ + if(plot !== this && plot.plotEvent){ + t.plot = plot; + plot.plotEvent(t); + } + }, this); + }, + connect: function(object, method){ + // summary: + // Helper function to connect any object's method to our plotEvent. + // object: Object + // The object to connect to. + // method: String|Function + // The method to fire when our plotEvent is fired. + // returns: Array + // The handle as returned from dojo.connect (see dojo.connect). + this.dirty = true; + return hub.connect(this, "plotEvent", object, method); // Array + }, + events: function(){ + // summary: + // Find out if any event handlers have been connected to our plotEvent. + // returns: Boolean + // A flag indicating that there are handlers attached. + return !!this.plotEvent.after; + }, + resetEvents: function(){ + // summary: + // Reset all events attached to our plotEvent (i.e. disconnect). + if(this._shapeEvents.length){ + arr.forEach(this._shapeEvents, function(item){ + item.shape.disconnect(item.handle); + }); + this._shapeEvents = []; + } + this.raiseEvent({type: "onplotreset", plot: this}); + }, + _connectSingleEvent: function(o, eventName){ + this._shapeEvents.push({ + shape: o.eventMask, + handle: o.eventMask.connect(eventName, this, function(e){ + o.type = eventName; + o.event = e; + this.raiseEvent(o); + o.event = null; + }) + }); + }, + _connectEvents: function(o){ + if(o){ + o.chart = this.chart; + o.plot = this; + o.hAxis = this.hAxis || null; + o.vAxis = this.vAxis || null; + o.eventMask = o.eventMask || o.shape; + this._connectSingleEvent(o, "onmouseover"); + this._connectSingleEvent(o, "onmouseout"); + this._connectSingleEvent(o, "onclick"); + } + }, + _reconnectEvents: function(seriesName){ + var a = this._eventSeries[seriesName]; + if(a){ + arr.forEach(a, this._connectEvents, this); + } + }, + fireEvent: function(seriesName, eventName, index, eventObject){ + // summary: + // Emulates firing an event for a given data value (specified by + // an index) of a given series. + // seriesName: String: + // Series name. + // eventName: String: + // Event name to emulate. + // index: Number: + // Valid data value index used to raise an event. + // eventObject: Object?: + // Optional event object. Especially useful for synthetic events. + // Default: null. + var s = this._eventSeries[seriesName]; + if(s && s.length && index < s.length){ + var o = s[index]; + o.type = eventName; + o.event = eventObject || null; + this.raiseEvent(o); + o.event = null; + } + } + }); +}); + +}, +'dojo/uacss':function(){ +define(["./dom-geometry", "./_base/lang", "./ready", "./_base/sniff", "./_base/window"], + function(geometry, lang, ready, has, baseWindow){ + // module: + // dojo/uacss + // summary: + // Applies pre-set CSS classes to the top-level HTML node, based on: + // - browser (ex: dj_ie) + // - browser version (ex: dj_ie6) + // - box model (ex: dj_contentBox) + // - text direction (ex: dijitRtl) + // + // In addition, browser, browser version, and box model are + // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl. + + var + html = baseWindow.doc.documentElement, + ie = has("ie"), + opera = has("opera"), + maj = Math.floor, + ff = has("ff"), + boxModel = geometry.boxModel.replace(/-/,''), + + classes = { + "dj_ie": ie, + "dj_ie6": maj(ie) == 6, + "dj_ie7": maj(ie) == 7, + "dj_ie8": maj(ie) == 8, + "dj_ie9": maj(ie) == 9, + "dj_quirks": has("quirks"), + "dj_iequirks": ie && has("quirks"), + + // NOTE: Opera not supported by dijit + "dj_opera": opera, + + "dj_khtml": has("khtml"), + + "dj_webkit": has("webkit"), + "dj_safari": has("safari"), + "dj_chrome": has("chrome"), + + "dj_gecko": has("mozilla"), + "dj_ff3": maj(ff) == 3 + }; // no dojo unsupported browsers + + classes["dj_" + boxModel] = true; + + // apply browser, browser version, and box model class names + var classStr = ""; + for(var clz in classes){ + if(classes[clz]){ + classStr += clz + " "; + } + } + html.className = lang.trim(html.className + " " + classStr); + + // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension. + // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl). + // priority is 90 to run ahead of parser priority of 100 + ready(90, function(){ + if(!geometry.isBodyLtr()){ + var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl "); + html.className = lang.trim(html.className + " " + rtlClassStr + "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")); + } + }); + return has; +}); + +}, +'dojox/charting/axis2d/Invisible':function(){ +define(["dojo/_base/lang", "dojo/_base/declare", "./Base", "../scaler/linear", + "dojox/gfx", "dojox/lang/utils", "dojox/lang/functional", "dojo/string"], + function(lang, declare, Base, lin, g, du, df, dstring){ +/*===== +var Base = dojox.charting.axis2d.Base; +=====*/ + var merge = du.merge, + labelGap = 4, // in pixels + centerAnchorLimit = 45; // in degrees + + return declare("dojox.charting.axis2d.Invisible", Base, { + // summary: + // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details. + // + // defaultParams: Object + // The default parameters used to define any axis. + // optionalParams: Object + // Any optional parameters needed to define an axis. + + /* + // TODO: the documentation tools need these to be pre-defined in order to pick them up + // correctly, but the code here is partially predicated on whether or not the properties + // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT + + // opt: Object + // The actual options used to define this axis, created at initialization. + // scalar: Object + // The calculated helper object to tell charts how to draw an axis and any data. + // ticks: Object + // The calculated tick object that helps a chart draw the scaling on an axis. + // dirty: Boolean + // The state of the axis (whether it needs to be redrawn or not) + // scale: Number + // The current scale of the axis. + // offset: Number + // The current offset of the axis. + + opt: null, + scalar: null, + ticks: null, + dirty: true, + scale: 1, + offset: 0, + */ + defaultParams: { + vertical: false, // true for vertical axis + fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none" + fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none" + natural: false, // all tick marks should be made on natural numbers + leftBottom: true, // position of the axis, used with "vertical" + includeZero: false, // 0 should be included + fixed: true, // all labels are fixed numbers + majorLabels: true, // draw major labels + minorTicks: true, // draw minor ticks + minorLabels: true, // draw minor labels + microTicks: false, // draw micro ticks + rotation: 0 // label rotation angle in degrees + }, + optionalParams: { + min: 0, // minimal value on this axis + max: 1, // maximal value on this axis + from: 0, // visible from this value + to: 1, // visible to this value + majorTickStep: 4, // major tick step + minorTickStep: 2, // minor tick step + microTickStep: 1, // micro tick step + labels: [], // array of labels for major ticks + // with corresponding numeric values + // ordered by values + labelFunc: null, // function to compute label values + maxLabelSize: 0, // size in px. For use with labelFunc + maxLabelCharCount: 0, // size in word count. + trailingSymbol: null + + // TODO: add support for minRange! + // minRange: 1, // smallest distance from min allowed on the axis + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for an axis. + // chart: dojox.charting.Chart + // The chart the axis belongs to. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // Any optional keyword arguments to be used to define this axis. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + }, + dependOnData: function(){ + // summary: + // Find out whether or not the axis options depend on the data in the axis. + return !("min" in this.opt) || !("max" in this.opt); // Boolean + }, + clear: function(){ + // summary: + // Clear out all calculated properties on this axis; + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + delete this.scaler; + delete this.ticks; + this.dirty = true; + return this; // dojox.charting.axis2d.Default + }, + initialized: function(){ + // summary: + // Finds out if this axis has been initialized or not. + // returns: Boolean + // Whether a scaler has been calculated and if the axis is not dirty. + return "scaler" in this && !(this.dirty && this.dependOnData()); + }, + setWindow: function(scale, offset){ + // summary: + // Set the drawing "window" for the axis. + // scale: Number + // The new scale for the axis. + // offset: Number + // The new offset for the axis. + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + this.scale = scale; + this.offset = offset; + return this.clear(); // dojox.charting.axis2d.Default + }, + getWindowScale: function(){ + // summary: + // Get the current windowing scale of the axis. + return "scale" in this ? this.scale : 1; // Number + }, + getWindowOffset: function(){ + // summary: + // Get the current windowing offset for the axis. + return "offset" in this ? this.offset : 0; // Number + }, + _groupLabelWidth: function(labels, font, wcLimit){ + if(!labels.length){ + return 0; + } + if(lang.isObject(labels[0])){ + labels = df.map(labels, function(label){ return label.text; }); + } + if (wcLimit) { + labels = df.map(labels, function(label){ + return lang.trim(label).length == 0 ? "" : label.substring(0, wcLimit) + this.trailingSymbol; + }, this); + } + var s = labels.join("<br>"); + return g._base._getTextBox(s, {font: font}).w || 0; + }, + calculate: function(min, max, span, labels){ + // summary: + // Perform all calculations needed to render this axis. + // min: Number + // The smallest value represented on this axis. + // max: Number + // The largest value represented on this axis. + // span: Number + // The span in pixels over which axis calculations are made. + // labels: String[] + // Optional list of labels. + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + if(this.initialized()){ + return this; + } + var o = this.opt; + this.labels = "labels" in o ? o.labels : labels; + this.scaler = lin.buildScaler(min, max, span, o); + var tsb = this.scaler.bounds; + if("scale" in this){ + // calculate new range + o.from = tsb.lower + this.offset; + o.to = (tsb.upper - tsb.lower) / this.scale + o.from; + // make sure that bounds are correct + if( !isFinite(o.from) || + isNaN(o.from) || + !isFinite(o.to) || + isNaN(o.to) || + o.to - o.from >= tsb.upper - tsb.lower + ){ + // any error --- remove from/to bounds + delete o.from; + delete o.to; + delete this.scale; + delete this.offset; + }else{ + // shift the window, if we are out of bounds + if(o.from < tsb.lower){ + o.to += tsb.lower - o.from; + o.from = tsb.lower; + }else if(o.to > tsb.upper){ + o.from += tsb.upper - o.to; + o.to = tsb.upper; + } + // update the offset + this.offset = o.from - tsb.lower; + } + // re-calculate the scaler + this.scaler = lin.buildScaler(min, max, span, o); + tsb = this.scaler.bounds; + // cleanup + if(this.scale == 1 && this.offset == 0){ + delete this.scale; + delete this.offset; + } + } + + var ta = this.chart.theme.axis, labelWidth = 0, rotation = o.rotation % 360, + // TODO: we use one font --- of major tick, we need to use major and minor fonts + taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), + sinr = Math.abs(Math.sin(rotation * Math.PI / 180)); + + if(rotation < 0){ + rotation += 360; + } + + if(size){ + if(this.vertical ? rotation != 0 && rotation != 180 : rotation != 90 && rotation != 270){ + // we need width of all labels + if(this.labels){ + labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount); + }else{ + var labelLength = Math.ceil( + Math.log( + Math.max( + Math.abs(tsb.from), + Math.abs(tsb.to) + ) + ) / Math.LN10 + ), + t = []; + if(tsb.from < 0 || tsb.to < 0){ + t.push("-"); + } + t.push(dstring.rep("9", labelLength)); + var precision = Math.floor( + Math.log( tsb.to - tsb.from ) / Math.LN10 + ); + if(precision > 0){ + t.push("."); + t.push(dstring.rep("9", precision)); + } + labelWidth = g._base._getTextBox( + t.join(""), + { font: taFont } + ).w; + } + labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth; + }else{ + labelWidth = size; + } + switch(rotation){ + case 0: + case 90: + case 180: + case 270: + // trivial cases: use labelWidth + break; + default: + // rotated labels + var gap1 = Math.sqrt(labelWidth * labelWidth + size * size), // short labels + gap2 = this.vertical ? size * cosr + labelWidth * sinr : labelWidth * cosr + size * sinr; // slanted labels + labelWidth = Math.min(gap1, gap2); + break; + } + } + + this.scaler.minMinorStep = labelWidth + labelGap; + this.ticks = lin.buildTicks(this.scaler, o); + return this; // dojox.charting.axis2d.Default + }, + getScaler: function(){ + // summary: + // Get the pre-calculated scaler object. + return this.scaler; // Object + }, + getTicks: function(){ + // summary: + // Get the pre-calculated ticks object. + return this.ticks; // Object + } + }); +}); + +}, +'dojox/lang/utils':function(){ +define("dojox/lang/utils", ["..", "dojo/_base/lang"], + function(dojox, lang){ + var du = lang.getObject("lang.utils", true, dojox); + + var empty = {}, opts = Object.prototype.toString; + + var clone = function(o){ + if(o){ + switch(opts.call(o)){ + case "[object Array]": + return o.slice(0); + case "[object Object]": + return lang.delegate(o); + } + } + return o; + } + + lang.mixin(du, { + coerceType: function(target, source){ + // summary: Coerces one object to the type of another. + // target: Object: object, which typeof result is used to coerce "source" object. + // source: Object: object, which will be forced to change type. + switch(typeof target){ + case "number": return Number(eval("(" + source + ")")); + case "string": return String(source); + case "boolean": return Boolean(eval("(" + source + ")")); + } + return eval("(" + source + ")"); + }, + + updateWithObject: function(target, source, conv){ + // summary: Updates an existing object in place with properties from an "source" object. + // target: Object: the "target" object to be updated + // source: Object: the "source" object, whose properties will be used to source the existed object. + // conv: Boolean?: force conversion to the original type + if(!source){ return target; } + for(var x in target){ + if(x in source && !(x in empty)){ + var t = target[x]; + if(t && typeof t == "object"){ + du.updateWithObject(t, source[x], conv); + }else{ + target[x] = conv ? du.coerceType(t, source[x]) : clone(source[x]); + } + } + } + return target; // Object + }, + + updateWithPattern: function(target, source, pattern, conv){ + // summary: Updates an existing object in place with properties from an "source" object. + // target: Object: the "target" object to be updated + // source: Object: the "source" object, whose properties will be used to source the existed object. + // pattern: Object: object, whose properties will be used to pull values from the "source" + // conv: Boolean?: force conversion to the original type + if(!source || !pattern){ return target; } + for(var x in pattern){ + if(x in source && !(x in empty)){ + target[x] = conv ? du.coerceType(pattern[x], source[x]) : clone(source[x]); + } + } + return target; // Object + }, + + merge: function(object, mixin){ + // summary: Merge two objects structurally, mixin properties will override object's properties. + // object: Object: original object. + // mixin: Object: additional object, which properties will override object's properties. + if(mixin){ + var otype = opts.call(object), mtype = opts.call(mixin), t, i, l, m; + switch(mtype){ + case "[object Array]": + if(mtype == otype){ + t = new Array(Math.max(object.length, mixin.length)); + for(i = 0, l = t.length; i < l; ++i){ + t[i] = du.merge(object[i], mixin[i]); + } + return t; + } + return mixin.slice(0); + case "[object Object]": + if(mtype == otype && object){ + t = lang.delegate(object); + for(i in mixin){ + if(i in object){ + l = object[i]; + m = mixin[i]; + if(m !== l){ + t[i] = du.merge(l, m); + } + }else{ + t[i] = lang.clone(mixin[i]); + } + } + return t; + } + return lang.clone(mixin); + } + } + return mixin; + } + }); + + return du; +}); + +}, +'dojox/charting/plot2d/Pie':function(){ +define("dojox/charting/plot2d/Pie", ["dojo/_base/lang", "dojo/_base/array" ,"dojo/_base/declare", + "../Element", "./_PlotEvents", "./common", "../axis2d/common", + "dojox/gfx", "dojox/gfx/matrix", "dojox/lang/functional", "dojox/lang/utils"], + function(lang, arr, declare, Element, PlotEvents, dc, da, g, m, df, du){ + + /*===== + var Element = dojox.charting.Element; + var PlotEvents = dojox.charting.plot2d._PlotEvents; + dojo.declare("dojox.charting.plot2d.__PieCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { + // summary: + // Specialized keyword arguments object for use in defining parameters on a Pie chart. + + // labels: Boolean? + // Whether or not to draw labels for each pie slice. Default is true. + labels: true, + + // ticks: Boolean? + // Whether or not to draw ticks to labels within each slice. Default is false. + ticks: false, + + // fixed: Boolean? + // TODO + fixed: true, + + // precision: Number? + // The precision at which to sum/add data values. Default is 1. + precision: 1, + + // labelOffset: Number? + // The amount in pixels by which to offset labels. Default is 20. + labelOffset: 20, + + // labelStyle: String? + // Options as to where to draw labels. Values include "default", and "columns". Default is "default". + labelStyle: "default", // default/columns + + // htmlLabels: Boolean? + // Whether or not to use HTML to render slice labels. Default is true. + htmlLabels: true, + + // radGrad: String? + // The type of radial gradient to use in rendering. Default is "native". + radGrad: "native", + + // fanSize: Number? + // The amount for a radial gradient. Default is 5. + fanSize: 5, + + // startAngle: Number? + // Where to being rendering gradients in slices, in degrees. Default is 0. + startAngle: 0, + + // radius: Number? + // The size of the radial gradient. Default is 0. + radius: 0 + }); + =====*/ + + var FUDGE_FACTOR = 0.2; // use to overlap fans + + return declare("dojox.charting.plot2d.Pie", [Element, PlotEvents], { + // summary: + // The plot that represents a typical pie chart. + defaultParams: { + labels: true, + ticks: false, + fixed: true, + precision: 1, + labelOffset: 20, + labelStyle: "default", // default/columns + htmlLabels: true, // use HTML to draw labels + radGrad: "native", // or "linear", or "fan" + fanSize: 5, // maximum fan size in degrees + startAngle: 0 // start angle for slices in degrees + }, + optionalParams: { + radius: 0, + // theme components + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "", + labelWiring: {} + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create a pie plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.run = null; + this.dyn = []; + }, + clear: function(){ + // summary: + // Clear out all of the information tied to this plot. + // returns: dojox.charting.plot2d.Pie + // A reference to this plot for functional chaining. + this.dirty = true; + this.dyn = []; + this.run = null; + return this; // dojox.charting.plot2d.Pie + }, + setAxis: function(axis){ + // summary: + // Dummy method, since axes are irrelevant with a Pie chart. + // returns: dojox.charting.plot2d.Pie + // The reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Pie + }, + addSeries: function(run){ + // summary: + // Add a series of data to this plot. + // returns: dojox.charting.plot2d.Pie + // The reference to this plot for functional chaining. + this.run = run; + return this; // dojox.charting.plot2d.Pie + }, + getSeriesStats: function(){ + // summary: + // Returns default stats (irrelevant for this type of plot). + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return lang.delegate(dc.defaultStats); + }, + initializeScalers: function(){ + // summary: + // Does nothing (irrelevant for this type of plot). + return this; + }, + getRequiredColors: function(){ + // summary: + // Return the number of colors needed to draw this plot. + return this.run ? this.run.data.length : 0; + }, + + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Pie + // A reference to this plot for functional chaining. + if(!this.dirty){ return this; } + this.resetEvents(); + this.dirty = false; + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group, t = this.chart.theme; + + if(!this.run || !this.run.data.length){ + return this; + } + + // calculate the geometry + var rx = (dim.width - offsets.l - offsets.r) / 2, + ry = (dim.height - offsets.t - offsets.b) / 2, + r = Math.min(rx, ry), + taFont = "font" in this.opt ? this.opt.font : t.axis.font, + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + taFontColor = "fontColor" in this.opt ? this.opt.fontColor : t.axis.fontColor, + startAngle = m._degToRad(this.opt.startAngle), + start = startAngle, step, filteredRun, slices, labels, shift, labelR, + run = this.run.data, + events = this.events(); + if(typeof run[0] == "number"){ + filteredRun = df.map(run, "x ? Math.max(x, 0) : 0"); + if(df.every(filteredRun, "<= 0")){ + return this; + } + slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); + if(this.opt.labels){ + labels = arr.map(slices, function(x){ + return x > 0 ? this._getLabel(x * 100) + "%" : ""; + }, this); + } + }else{ + filteredRun = df.map(run, "x ? Math.max(x.y, 0) : 0"); + if(df.every(filteredRun, "<= 0")){ + return this; + } + slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); + if(this.opt.labels){ + labels = arr.map(slices, function(x, i){ + if(x <= 0){ return ""; } + var v = run[i]; + return "text" in v ? v.text : this._getLabel(x * 100) + "%"; + }, this); + } + } + var themes = df.map(run, function(v, i){ + if(v === null || typeof v == "number"){ + return t.next("slice", [this.opt, this.run], true); + } + return t.next("slice", [this.opt, this.run, v], true); + }, this); + if(this.opt.labels){ + shift = df.foldl1(df.map(labels, function(label, i){ + var font = themes[i].series.font; + return g._base._getTextBox(label, {font: font}).w; + }, this), "Math.max(a, b)") / 2; + if(this.opt.labelOffset < 0){ + r = Math.min(rx - 2 * shift, ry - size) + this.opt.labelOffset; + } + labelR = r - this.opt.labelOffset; + } + if("radius" in this.opt){ + r = this.opt.radius; + labelR = r - this.opt.labelOffset; + } + var circle = { + cx: offsets.l + rx, + cy: offsets.t + ry, + r: r + }; + + this.dyn = []; + // draw slices + var eventSeries = new Array(slices.length); + arr.some(slices, function(slice, i){ + if(slice < 0){ + // degenerated slice + return false; // continue + } + if(slice == 0){ + this.dyn.push({fill: null, stroke: null}); + return false; + } + var v = run[i], theme = themes[i], specialFill; + if(slice >= 1){ + // whole pie + specialFill = this._plotFill(theme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, + { + x: circle.cx - circle.r, y: circle.cy - circle.r, + width: 2 * circle.r, height: 2 * circle.r + }); + specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, circle.r); + var shape = s.createCircle(circle).setFill(specialFill).setStroke(theme.series.stroke); + this.dyn.push({fill: specialFill, stroke: theme.series.stroke}); + + if(events){ + var o = { + element: "slice", + index: i, + run: this.run, + shape: shape, + x: i, + y: typeof v == "number" ? v : v.y, + cx: circle.cx, + cy: circle.cy, + cr: r + }; + this._connectEvents(o); + eventSeries[i] = o; + } + + return true; // stop iteration + } + // calculate the geometry of the slice + var end = start + slice * 2 * Math.PI; + if(i + 1 == slices.length){ + end = startAngle + 2 * Math.PI; + } + var step = end - start, + x1 = circle.cx + r * Math.cos(start), + y1 = circle.cy + r * Math.sin(start), + x2 = circle.cx + r * Math.cos(end), + y2 = circle.cy + r * Math.sin(end); + // draw the slice + var fanSize = m._degToRad(this.opt.fanSize); + if(theme.series.fill && theme.series.fill.type === "radial" && this.opt.radGrad === "fan" && step > fanSize){ + var group = s.createGroup(), nfans = Math.ceil(step / fanSize), delta = step / nfans; + specialFill = this._shapeFill(theme.series.fill, + {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r}); + for(var j = 0; j < nfans; ++j){ + var fansx = j == 0 ? x1 : circle.cx + r * Math.cos(start + (j - FUDGE_FACTOR) * delta), + fansy = j == 0 ? y1 : circle.cy + r * Math.sin(start + (j - FUDGE_FACTOR) * delta), + fanex = j == nfans - 1 ? x2 : circle.cx + r * Math.cos(start + (j + 1 + FUDGE_FACTOR) * delta), + faney = j == nfans - 1 ? y2 : circle.cy + r * Math.sin(start + (j + 1 + FUDGE_FACTOR) * delta), + fan = group.createPath(). + moveTo(circle.cx, circle.cy). + lineTo(fansx, fansy). + arcTo(r, r, 0, delta > Math.PI, true, fanex, faney). + lineTo(circle.cx, circle.cy). + closePath(). + setFill(this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start + (j + 0.5) * delta, start + (j + 0.5) * delta)); + } + group.createPath(). + moveTo(circle.cx, circle.cy). + lineTo(x1, y1). + arcTo(r, r, 0, step > Math.PI, true, x2, y2). + lineTo(circle.cx, circle.cy). + closePath(). + setStroke(theme.series.stroke); + shape = group; + }else{ + shape = s.createPath(). + moveTo(circle.cx, circle.cy). + lineTo(x1, y1). + arcTo(r, r, 0, step > Math.PI, true, x2, y2). + lineTo(circle.cx, circle.cy). + closePath(). + setStroke(theme.series.stroke); + var specialFill = theme.series.fill; + if(specialFill && specialFill.type === "radial"){ + specialFill = this._shapeFill(specialFill, {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r}); + if(this.opt.radGrad === "linear"){ + specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start, end); + } + }else if(specialFill && specialFill.type === "linear"){ + specialFill = this._plotFill(specialFill, dim, offsets); + specialFill = this._shapeFill(specialFill, shape.getBoundingBox()); + } + shape.setFill(specialFill); + } + this.dyn.push({fill: specialFill, stroke: theme.series.stroke}); + + if(events){ + var o = { + element: "slice", + index: i, + run: this.run, + shape: shape, + x: i, + y: typeof v == "number" ? v : v.y, + cx: circle.cx, + cy: circle.cy, + cr: r + }; + this._connectEvents(o); + eventSeries[i] = o; + } + + start = end; + + return false; // continue + }, this); + // draw labels + if(this.opt.labels){ + if(this.opt.labelStyle == "default"){ + start = startAngle; + arr.some(slices, function(slice, i){ + if(slice <= 0){ + // degenerated slice + return false; // continue + } + var theme = themes[i]; + if(slice >= 1){ + // whole pie + var v = run[i], elem = da.createText[this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"]( + this.chart, s, circle.cx, circle.cy + size / 2, "middle", labels[i], + theme.series.font, theme.series.fontColor); + if(this.opt.htmlLabels){ + this.htmlElements.push(elem); + } + return true; // stop iteration + } + // calculate the geometry of the slice + var end = start + slice * 2 * Math.PI, v = run[i]; + if(i + 1 == slices.length){ + end = startAngle + 2 * Math.PI; + } + var labelAngle = (start + end) / 2, + x = circle.cx + labelR * Math.cos(labelAngle), + y = circle.cy + labelR * Math.sin(labelAngle) + size / 2; + // draw the label + var elem = da.createText[this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"] + (this.chart, s, x, y, "middle", labels[i], theme.series.font, theme.series.fontColor); + if(this.opt.htmlLabels){ + this.htmlElements.push(elem); + } + start = end; + return false; // continue + }, this); + }else if(this.opt.labelStyle == "columns"){ + start = startAngle; + //calculate label angles + var labeledSlices = []; + arr.forEach(slices, function(slice, i){ + var end = start + slice * 2 * Math.PI; + if(i + 1 == slices.length){ + end = startAngle + 2 * Math.PI; + } + var labelAngle = (start + end) / 2; + labeledSlices.push({ + angle: labelAngle, + left: Math.cos(labelAngle) < 0, + theme: themes[i], + index: i, + omit: end - start < 0.001 + }); + start = end; + }); + //calculate label radius to each slice + var labelHeight = g._base._getTextBox("a",{font:taFont}).h; + this._getProperLabelRadius(labeledSlices, labelHeight, circle.r * 1.1); + //draw label and wiring + arr.forEach(labeledSlices, function(slice, i){ + if (!slice.omit) { + var leftColumn = circle.cx - circle.r * 2, + rightColumn = circle.cx + circle.r * 2, + labelWidth = g._base._getTextBox(labels[i], {font: taFont}).w, + x = circle.cx + slice.labelR * Math.cos(slice.angle), + y = circle.cy + slice.labelR * Math.sin(slice.angle), + jointX = (slice.left) ? (leftColumn + labelWidth) : (rightColumn - labelWidth), + labelX = (slice.left) ? leftColumn : jointX; + var wiring = s.createPath().moveTo(circle.cx + circle.r * Math.cos(slice.angle), circle.cy + circle.r * Math.sin(slice.angle)) + if (Math.abs(slice.labelR * Math.cos(slice.angle)) < circle.r * 2 - labelWidth) { + wiring.lineTo(x, y); + } + wiring.lineTo(jointX, y).setStroke(slice.theme.series.labelWiring); + var elem = da.createText[this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"]( + this.chart, s, labelX, y, "left", labels[i], slice.theme.series.font, slice.theme.series.fontColor); + if (this.opt.htmlLabels) { + this.htmlElements.push(elem); + } + } + },this); + } + } + // post-process events to restore the original indexing + var esi = 0; + this._eventSeries[this.run.name] = df.map(run, function(v){ + return v <= 0 ? null : eventSeries[esi++]; + }); + return this; // dojox.charting.plot2d.Pie + }, + + _getProperLabelRadius: function(slices, labelHeight, minRidius){ + var leftCenterSlice = {},rightCenterSlice = {},leftMinSIN = 1, rightMinSIN = 1; + if (slices.length == 1) { + slices[0].labelR = minRidius; + return; + } + for(var i = 0;i<slices.length;i++){ + var tempSIN = Math.abs(Math.sin(slices[i].angle)); + if(slices[i].left){ + if(leftMinSIN > tempSIN){ + leftMinSIN = tempSIN; + leftCenterSlice = slices[i]; + } + }else{ + if(rightMinSIN > tempSIN){ + rightMinSIN = tempSIN; + rightCenterSlice = slices[i]; + } + } + } + leftCenterSlice.labelR = rightCenterSlice.labelR = minRidius; + this._calculateLabelR(leftCenterSlice,slices,labelHeight); + this._calculateLabelR(rightCenterSlice,slices,labelHeight); + }, + _calculateLabelR: function(firstSlice,slices,labelHeight){ + var i = firstSlice.index,length = slices.length, + currentLabelR = firstSlice.labelR; + while(!(slices[i%length].left ^ slices[(i+1)%length].left)){ + if (!slices[(i + 1) % length].omit) { + var nextLabelR = (Math.sin(slices[i % length].angle) * currentLabelR + ((slices[i % length].left) ? (-labelHeight) : labelHeight)) / + Math.sin(slices[(i + 1) % length].angle); + currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR; + slices[(i + 1) % length].labelR = currentLabelR; + } + i++; + } + i = firstSlice.index; + var j = (i == 0)?length-1 : i - 1; + while(!(slices[i].left ^ slices[j].left)){ + if (!slices[j].omit) { + var nextLabelR = (Math.sin(slices[i].angle) * currentLabelR + ((slices[i].left) ? labelHeight : (-labelHeight))) / + Math.sin(slices[j].angle); + currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR; + slices[j].labelR = currentLabelR; + } + i--;j--; + i = (i < 0)?i+slices.length:i; + j = (j < 0)?j+slices.length:j; + } + }, + // utilities + _getLabel: function(number){ + return dc.getLabel(number, this.opt.fixed, this.opt.precision); + } + }); +}); + +}, +'dijit/hccss':function(){ +define("dijit/hccss", [ + "require", // require.toUrl + "dojo/_base/config", // config.blankGif + "dojo/dom-class", // domClass.add domConstruct.create domStyle.getComputedStyle + "dojo/dom-construct", // domClass.add domConstruct.create domStyle.getComputedStyle + "dojo/dom-style", // domClass.add domConstruct.create domStyle.getComputedStyle + "dojo/ready", // ready + "dojo/_base/sniff", // has("ie") has("mozilla") + "dojo/_base/window" // win.body +], function(require, config, domClass, domConstruct, domStyle, ready, has, win){ + + // module: + // dijit/hccss + // summary: + // Test if computer is in high contrast mode, and sets dijit_a11y flag on <body> if it is. + + if(has("ie") || has("mozilla")){ // NOTE: checking in Safari messes things up + // priority is 90 to run ahead of parser priority of 100 + ready(90, function(){ + // summary: + // Detects if we are in high-contrast mode or not + + // create div for testing if high contrast mode is on or images are turned off + var div = domConstruct.create("div",{ + id: "a11yTestNode", + style:{ + cssText:'border: 1px solid;' + + 'border-color:red green;' + + 'position: absolute;' + + 'height: 5px;' + + 'top: -999px;' + + 'background-image: url("' + (config.blankGif || require.toUrl("dojo/resources/blank.gif")) + '");' + } + }, win.body()); + + // test it + var cs = domStyle.getComputedStyle(div); + if(cs){ + var bkImg = cs.backgroundImage; + var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" )); + if(needsA11y){ + domClass.add(win.body(), "dijit_a11y"); + } + if(has("ie")){ + div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014 + }else{ + win.body().removeChild(div); + } + } + }); + } +}); + +}, +'dojox/charting/action2d/Shake':function(){ +define("dojox/charting/action2d/Shake", ["dojo/_base/connect", "dojo/_base/declare", "./PlotAction", + "dojo/fx", "dojo/fx/easing", "dojox/gfx/matrix", "dojox/gfx/fx"], + function(hub, declare, PlotAction, df, dfe, m, gf){ + + /*===== + dojo.declare("dojox.charting.action2d.__ShakeCtorArgs", dojox.charting.action2d.__PlotActionCtorArgstorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // shift: Number? + // The amount in pixels to shift the pie slice. Default is 3. + shift: 3 + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SHIFT = 3; + + return declare("dojox.charting.action2d.Shake", PlotAction, { + // summary: + // Create a shaking action for use on an element in a chart. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut, // easing for the action + shiftX: DEFAULT_SHIFT, // shift of the element along the X axis + shiftY: DEFAULT_SHIFT // shift of the element along the Y axis + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the shaking action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__ShakeCtorArgs? + // Optional keyword arguments object for setting parameters. + if(!kwArgs){ kwArgs = {}; } + this.shiftX = typeof kwArgs.shiftX == "number" ? kwArgs.shiftX : DEFAULT_SHIFT; + this.shiftY = typeof kwArgs.shiftY == "number" ? kwArgs.shiftY : DEFAULT_SHIFT; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the slice moving action. + if(!o.shape || !(o.type in this.overOutEvents)){ return; } + + var runName = o.run.name, index = o.index, vector = [], anim, + shiftX = o.type == "onmouseover" ? this.shiftX : -this.shiftX, + shiftY = o.type == "onmouseover" ? this.shiftY : -this.shiftY; + + if(runName in this.anim){ + anim = this.anim[runName][index]; + }else{ + this.anim[runName] = {}; + } + + if(anim){ + anim.action.stop(true); + }else{ + this.anim[runName][index] = anim = {}; + } + + var kwArgs = { + shape: o.shape, + duration: this.duration, + easing: this.easing, + transform: [ + {name: "translate", start: [this.shiftX, this.shiftY], end: [0, 0]}, + m.identity + ] + }; + if(o.shape){ + vector.push(gf.animateTransform(kwArgs)); + } + if(o.oultine){ + kwArgs.shape = o.outline; + vector.push(gf.animateTransform(kwArgs)); + } + if(o.shadow){ + kwArgs.shape = o.shadow; + vector.push(gf.animateTransform(kwArgs)); + } + + if(!vector.length){ + delete this.anim[runName][index]; + return; + } + + anim.action = df.combine(vector); + if(o.type == "onmouseout"){ + hub.connect(anim.action, "onEnd", this, function(){ + if(this.anim[runName]){ + delete this.anim[runName][index]; + } + }); + } + anim.action.play(); + } + }); +}); + +}, +'dojox/lang/functional/lambda':function(){ +define("dojox/lang/functional/lambda", ["../..", "dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array"], function(dojox, dojo, lang, arr){ + var df = lang.getObject("lang.functional", true, dojox); + +// This module adds high-level functions and related constructs: +// - anonymous functions built from the string + +// Acknoledgements: +// - lambda() is based on work by Oliver Steele +// (http://osteele.com/sources/javascript/functional/functional.js) +// which was published under MIT License + +// Notes: +// - lambda() produces functions, which after the compilation step are +// as fast as regular JS functions (at least theoretically). + +// Lambda input values: +// - returns functions unchanged +// - converts strings to functions +// - converts arrays to a functional composition + + var lcache = {}; + + // split() is augmented on IE6 to ensure the uniform behavior + var split = "ab".split(/a*/).length > 1 ? String.prototype.split : + function(sep){ + var r = this.split.call(this, sep), + m = sep.exec(this); + if(m && m.index == 0){ r.unshift(""); } + return r; + }; + + var lambda = function(/*String*/ s){ + var args = [], sects = split.call(s, /\s*->\s*/m); + if(sects.length > 1){ + while(sects.length){ + s = sects.pop(); + args = sects.pop().split(/\s*,\s*|\s+/m); + if(sects.length){ sects.push("(function(" + args + "){return (" + s + ")})"); } + } + }else if(s.match(/\b_\b/)){ + args = ["_"]; + }else{ + var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), + r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); + if(l || r){ + if(l){ + args.push("$1"); + s = "$1" + s; + } + if(r){ + args.push("$2"); + s = s + "$2"; + } + }else{ + // the point of the long regex below is to exclude all well-known + // lower-case words from the list of potential arguments + var vars = s. + replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|dojo|dijit|dojox|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, ""). + match(/([a-z_$][a-z_$\d]*)/gi) || [], t = {}; + arr.forEach(vars, function(v){ + if(!(v in t)){ + args.push(v); + t[v] = 1; + } + }); + } + } + return {args: args, body: s}; // Object + }; + + var compose = function(/*Array*/ a){ + return a.length ? + function(){ + var i = a.length - 1, x = df.lambda(a[i]).apply(this, arguments); + for(--i; i >= 0; --i){ x = df.lambda(a[i]).call(this, x); } + return x; + } + : + // identity + function(x){ return x; }; + }; + + lang.mixin(df, { + // lambda + rawLambda: function(/*String*/ s){ + // summary: + // builds a function from a snippet, or array (composing), + // returns an object describing the function; functions are + // passed through unmodified. + // description: + // This method is to normalize a functional representation (a + // text snippet) to an object that contains an array of + // arguments, and a body , which is used to calculate the + // returning value. + return lambda(s); // Object + }, + buildLambda: function(/*String*/ s){ + // summary: + // builds a function from a snippet, returns a string, which + // represents the function. + // description: + // This method returns a textual representation of a function + // built from the snippet. It is meant to be evaled in the + // proper context, so local variables can be pulled from the + // environment. + s = lambda(s); + return "function(" + s.args.join(",") + "){return (" + s.body + ");}"; // String + }, + lambda: function(/*Function|String|Array*/ s){ + // summary: + // builds a function from a snippet, or array (composing), + // returns a function object; functions are passed through + // unmodified. + // description: + // This method is used to normalize a functional + // representation (a text snippet, an array, or a function) to + // a function object. + if(typeof s == "function"){ return s; } + if(s instanceof Array){ return compose(s); } + if(s in lcache){ return lcache[s]; } + s = lambda(s); + return lcache[s] = new Function(s.args, "return (" + s.body + ");"); // Function + }, + clearLambdaCache: function(){ + // summary: + // clears internal cache of lambdas + lcache = {}; + } + }); + + return df; +}); + +}, +'dojox/lang/functional/reversed':function(){ +define(["dojo/_base/lang", "dojo/_base/window" ,"./lambda"], + function(lang, win, df){ +// This module adds high-level functions and related constructs: +// - reversed versions of array-processing functions similar to standard JS functions + +// Notes: +// - this module provides reversed versions of standard array-processing functions: +// forEachRev, mapRev, filterRev + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument + +/*===== + var df = dojox.lang.functional; + =====*/ + lang.mixin(df, { + // JS 1.6 standard array functions, which can take a lambda as a parameter. + // Consider using dojo._base.array functions, if you don't need the lambda support. + filterRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with all elements that pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var t = [], v, i = a.length - 1; + for(; i >= 0; --i){ + v = a[i]; + if(f.call(o, v, i, a)){ t.push(v); } + } + return t; // Array + }, + forEachRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: executes a provided function once per array element. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + for(var i = a.length - 1; i >= 0; f.call(o, a[i], i, a), --i); + }, + mapRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with the results of calling + // a provided function on every element in this array. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var n = a.length, t = new Array(n), i = n - 1, j = 0; + for(; i >= 0; t[j++] = f.call(o, a[i], i, a), --i); + return t; // Array + }, + everyRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether all elements in the array pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + for(var i = a.length - 1; i >= 0; --i){ + if(!f.call(o, a[i], i, a)){ + return false; // Boolean + } + } + return true; // Boolean + }, + someRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether some element in the array passes the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + for(var i = a.length - 1; i >= 0; --i){ + if(f.call(o, a[i], i, a)){ + return true; // Boolean + } + } + return false; // Boolean + } + }); + + return df; +}); + +}, +'dojox/charting/scaler/primitive':function(){ +define("dojox/charting/scaler/primitive", ["dojo/_base/lang"], + function(lang){ + var primitive = lang.getObject("dojox.charting.scaler.primitive", true); + return lang.mixin(primitive, { + buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){ + if(min == max){ + // artificially extend bounds + min -= 0.5; + max += 0.5; + // now the line will be centered + } + return { + bounds: { + lower: min, + upper: max, + from: min, + to: max, + scale: span / (max - min), + span: span + }, + scaler: primitive + }; + }, + buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){ + return {major: [], minor: [], micro: []}; // Object + }, + getTransformerFromModel: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return (x - offset) * scale; }; // Function + }, + getTransformerFromPlot: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return x / scale + offset; }; // Function + } + }); +}); + +}, +'dojox/charting/plot2d/Candlesticks':function(){ +define("dojox/charting/plot2d/Candlesticks", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, arr, Base, dc, df, dfr, du, fx){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + // Candlesticks are based on the Bars plot type; we expect the following passed + // as values in a series: + // { x?, open, close, high, low, mid? } + // if x is not provided, the array index is used. + // failing to provide the OHLC values will throw an error. + return declare("dojox.charting.plot2d.Candlesticks", Base, { + // summary: + // A plot that represents typical candlesticks (financial reporting, primarily). + // Unlike most charts, the Candlestick expects data points to be represented by + // an object of the form { x?, open, close, high, low, mid? }, where both + // x and mid are optional parameters. If x is not provided, the index of the + // data array is used. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 2, // gap between columns in pixels + animate: null // animate bars into place + }, + optionalParams: { + minBarSize: 1, // minimal candle width in pixels + maxBarSize: 1, // maximal candle width in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a candlestick chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + collectStats: function(series){ + // summary: + // Collect all statistics for drawing this chart. Since the common + // functionality only assumes x and y, Candlesticks must create it's own + // stats (since data has no y value, but open/close/high/low instead). + // series: dojox.charting.Series[] + // The data series array to be drawn on this plot. + // returns: Object + // Returns an object in the form of { hmin, hmax, vmin, vmax }. + + // we have to roll our own, since we need to use all four passed + // values to figure out our stats, and common only assumes x and y. + var stats = lang.delegate(dc.defaultStats); + for(var i=0; i<series.length; i++){ + var run = series[i]; + if(!run.data.length){ continue; } + var old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, idx){ + if(val !== null){ + var x = val.x || idx + 1; + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low); + stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low); + } + }); + } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + } + return stats; // Object + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = this.collectStats(this.series); + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Candlesticks + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("candlestick", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + var finalTheme = t.addMixin(theme, "candlestick", v, true); + + // calculate the points we need for OHLC + var x = ht(v.x || (j+0.5)) + offsets.l + gap, + y = dim.height - offsets.b, + open = vt(v.open), + close = vt(v.close), + high = vt(v.high), + low = vt(v.low); + if("mid" in v){ + var mid = vt(v.mid); + } + if(low > high){ + var tmp = high; + high = low; + low = tmp; + } + + if(width >= 1){ + // draw the line and rect, set up as a group and pass that to the events. + var doFill = open > close; + var line = { x1: width/2, x2: width/2, y1: y - high, y2: y - low }, + rect = { + x: 0, y: y-Math.max(open, close), + width: width, height: Math.max(doFill ? open-close : close-open, 1) + }; + var shape = s.createGroup(); + shape.setTransform({dx: x, dy: 0 }); + var inner = shape.createGroup(); + inner.createLine(line).setStroke(finalTheme.series.stroke); + inner.createRect(rect).setStroke(finalTheme.series.stroke). + setFill(doFill ? finalTheme.series.fill : "white"); + if("mid" in v){ + // add the mid line. + inner.createLine({ + x1: (finalTheme.series.stroke.width||1), x2: width - (finalTheme.series.stroke.width || 1), + y1: y - mid, y2: y - mid + }).setStroke(doFill ? "white" : finalTheme.series.stroke); + } + + // TODO: double check this. + run.dyn.fill = finalTheme.series.fill; + run.dyn.stroke = finalTheme.series.stroke; + if(events){ + var o = { + element: "candlestick", + index: j, + run: run, + shape: inner, + x: x, + y: y-Math.max(open, close), + cx: width/2, + cy: (y-Math.max(open, close)) + (Math.max(doFill ? open-close : close-open, 1)/2), + width: width, + height: Math.max(doFill ? open-close : close-open, 1), + data: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + } + if(this.animate){ + this._animateCandlesticks(shape, y - low, high - low); + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Candlesticks + }, + _animateCandlesticks: function(shape, voffset, vsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]}, + {name: "scale", start: [1, 1/vsize], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); + +}, +'dojox/charting/widget/Sparkline':function(){ +define("dojox/charting/widget/Sparkline", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/_base/html", "dojo/query", + "./Chart", "../themes/GreySkies", "../plot2d/Lines", "dojo/dom-prop"], + function(lang, arrayUtil, declare, html, query, Chart, GreySkies, Lines, domProp){ +/*===== +var Chart = dojox.charting.widget.Chart; +=====*/ + + declare("dojox.charting.widget.Sparkline", Chart, { + theme: GreySkies, + margins: { l: 0, r: 0, t: 0, b: 0 }, + type: "Lines", + valueFn: "Number(x)", + store: "", + field: "", + query: "", + queryOptions: "", + start: "0", + count: "Infinity", + sort: "", + data: "", + name: "default", + buildRendering: function(){ + var n = this.srcNodeRef; + if( !n.childNodes.length || // shortcut the query + !query("> .axis, > .plot, > .action, > .series", n).length){ + var plot = document.createElement("div"); + domProp.set(plot, { + "class": "plot", + "name": "default", + "type": this.type + }); + n.appendChild(plot); + + var series = document.createElement("div"); + domProp.set(series, { + "class": "series", + plot: "default", + name: this.name, + start: this.start, + count: this.count, + valueFn: this.valueFn + }); + arrayUtil.forEach( + ["store", "field", "query", "queryOptions", "sort", "data"], + function(i){ + if(this[i].length){ + domProp.set(series, i, this[i]); + } + }, + this + ); + n.appendChild(series); + } + this.inherited(arguments); + } + } + ); +}); + +}, +'dojox/gfx/matrix':function(){ +define("dojox/gfx/matrix", ["./_base","dojo/_base/lang"], + function(g, lang){ + var m = g.matrix = {}; + /*===== g = dojox.gfx; m = dojox.gfx.matrix =====*/ + + // candidates for dojox.math: + var _degToRadCache = {}; + m._degToRad = function(degree){ + return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180)); + }; + m._radToDeg = function(radian){ return radian / Math.PI * 180; }; + + m.Matrix2D = function(arg){ + // summary: + // a 2D matrix object + // description: Normalizes a 2D matrix-like object. If arrays is passed, + // all objects of the array are normalized and multiplied sequentially. + // arg: Object + // a 2D matrix-like object, a number, or an array of such objects + if(arg){ + if(typeof arg == "number"){ + this.xx = this.yy = arg; + }else if(arg instanceof Array){ + if(arg.length > 0){ + var matrix = m.normalize(arg[0]); + // combine matrices + for(var i = 1; i < arg.length; ++i){ + var l = matrix, r = m.normalize(arg[i]); + matrix = new m.Matrix2D(); + matrix.xx = l.xx * r.xx + l.xy * r.yx; + matrix.xy = l.xx * r.xy + l.xy * r.yy; + matrix.yx = l.yx * r.xx + l.yy * r.yx; + matrix.yy = l.yx * r.xy + l.yy * r.yy; + matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx; + matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy; + } + lang.mixin(this, matrix); + } + }else{ + lang.mixin(this, arg); + } + } + }; + + // the default (identity) matrix, which is used to fill in missing values + lang.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0}); + + lang.mixin(m, { + // summary: class constants, and methods of dojox.gfx.matrix + + // matrix constants + + // identity: dojox.gfx.matrix.Matrix2D + // an identity matrix constant: identity * (x, y) == (x, y) + identity: new m.Matrix2D(), + + // flipX: dojox.gfx.matrix.Matrix2D + // a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y) + flipX: new m.Matrix2D({xx: -1}), + + // flipY: dojox.gfx.matrix.Matrix2D + // a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y) + flipY: new m.Matrix2D({yy: -1}), + + // flipXY: dojox.gfx.matrix.Matrix2D + // a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y) + flipXY: new m.Matrix2D({xx: -1, yy: -1}), + + // matrix creators + + translate: function(a, b){ + // summary: forms a translation matrix + // description: The resulting matrix is used to translate (move) points by specified offsets. + // a: Number: an x coordinate value + // b: Number: a y coordinate value + if(arguments.length > 1){ + return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions + // b: null + return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D + }, + scale: function(a, b){ + // summary: forms a scaling matrix + // description: The resulting matrix is used to scale (magnify) points by specified offsets. + // a: Number: a scaling factor used for the x coordinate + // b: Number: a scaling factor used for the y coordinate + if(arguments.length > 1){ + return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D + } + if(typeof a == "number"){ + // branch + // a: Number: a uniform scaling factor used for the both coordinates + // b: null + return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions + // b: null + return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D + }, + rotate: function(angle){ + // summary: forms a rotating matrix + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an angle of rotation in radians (>0 for CW) + var c = Math.cos(angle); + var s = Math.sin(angle); + return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D + }, + rotateg: function(degree){ + // summary: forms a rotating matrix + // description: The resulting matrix is used to rotate points + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx.matrix.rotate() for comparison. + // degree: Number: an angle of rotation in degrees (>0 for CW) + return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D + }, + skewX: function(angle) { + // summary: forms an x skewing matrix + // description: The resulting matrix is used to skew points in the x dimension + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an skewing angle in radians + return new m.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D + }, + skewXg: function(degree){ + // summary: forms an x skewing matrix + // description: The resulting matrix is used to skew points in the x dimension + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx.matrix.skewX() for comparison. + // degree: Number: an skewing angle in degrees + return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D + }, + skewY: function(angle){ + // summary: forms a y skewing matrix + // description: The resulting matrix is used to skew points in the y dimension + // around the origin of coordinates (0, 0) by specified angle. + // angle: Number: an skewing angle in radians + return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D + }, + skewYg: function(degree){ + // summary: forms a y skewing matrix + // description: The resulting matrix is used to skew points in the y dimension + // around the origin of coordinates (0, 0) by specified degree. + // See dojox.gfx.matrix.skewY() for comparison. + // degree: Number: an skewing angle in degrees + return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D + }, + reflect: function(a, b){ + // summary: forms a reflection matrix + // description: The resulting matrix is used to reflect points around a vector, + // which goes through the origin. + // a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection + // b: null + if(arguments.length == 1){ + b = a.y; + a = a.x; + } + // branch + // a: Number: an x coordinate value + // b: Number: a y coordinate value + + // make a unit vector + var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2; + return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D + }, + project: function(a, b){ + // summary: forms an orthogonal projection matrix + // description: The resulting matrix is used to project points orthogonally on a vector, + // which goes through the origin. + // a: dojox.gfx.Point: a point-like object, which specifies a vector of projection + // b: null + if(arguments.length == 1){ + b = a.y; + a = a.x; + } + // branch + // a: Number: an x coordinate value + // b: Number: a y coordinate value + + // make a unit vector + var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2; + return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D + }, + + // ensure matrix 2D conformance + normalize: function(matrix){ + // summary: converts an object to a matrix, if necessary + // description: Converts any 2D matrix-like object or an array of + // such objects to a valid dojox.gfx.matrix.Matrix2D object. + // matrix: Object: an object, which is converted to a matrix, if necessary + return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D + }, + + // common operations + + clone: function(matrix){ + // summary: creates a copy of a 2D matrix + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned + var obj = new m.Matrix2D(); + for(var i in matrix){ + if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i]; + } + return obj; // dojox.gfx.matrix.Matrix2D + }, + invert: function(matrix){ + // summary: inverts a 2D matrix + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted + var M = m.normalize(matrix), + D = M.xx * M.yy - M.xy * M.yx; + M = new m.Matrix2D({ + xx: M.yy/D, xy: -M.xy/D, + yx: -M.yx/D, yy: M.xx/D, + dx: (M.xy * M.dy - M.yy * M.dx) / D, + dy: (M.yx * M.dx - M.xx * M.dy) / D + }); + return M; // dojox.gfx.matrix.Matrix2D + }, + _multiplyPoint: function(matrix, x, y){ + // summary: applies a matrix to a point + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied + // x: Number: an x coordinate of a point + // y: Number: a y coordinate of a point + return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point + }, + multiplyPoint: function(matrix, /* Number||Point */ a, /* Number? */ b){ + // summary: applies a matrix to a point + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied + // a: Number: an x coordinate of a point + // b: Number?: a y coordinate of a point + var M = m.normalize(matrix); + if(typeof a == "number" && typeof b == "number"){ + return m._multiplyPoint(M, a, b); // dojox.gfx.Point + } + // branch + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied + // a: dojox.gfx.Point: a point + // b: null + return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point + }, + multiply: function(matrix){ + // summary: combines matrices by multiplying them sequentially in the given order + // matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object, + // all subsequent arguments are matrix-like objects too + var M = m.normalize(matrix); + // combine matrices + for(var i = 1; i < arguments.length; ++i){ + var l = M, r = m.normalize(arguments[i]); + M = new m.Matrix2D(); + M.xx = l.xx * r.xx + l.xy * r.yx; + M.xy = l.xx * r.xy + l.xy * r.yy; + M.yx = l.yx * r.xx + l.yy * r.yx; + M.yy = l.yx * r.xy + l.yy * r.yy; + M.dx = l.xx * r.dx + l.xy * r.dy + l.dx; + M.dy = l.yx * r.dx + l.yy * r.dy + l.dy; + } + return M; // dojox.gfx.matrix.Matrix2D + }, + + // high level operations + + _sandwich: function(matrix, x, y){ + // summary: applies a matrix at a centrtal point + // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point + // x: Number: an x component of the central point + // y: Number: a y component of the central point + return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D + }, + scaleAt: function(a, b, c, d){ + // summary: scales a picture using a specified point as a center of scaling + // description: Compare with dojox.gfx.matrix.scale(). + // a: Number: a scaling factor used for the x coordinate + // b: Number: a scaling factor used for the y coordinate + // c: Number: an x component of a central point + // d: Number: a y component of a central point + + // accepts several signatures: + // 1) uniform scale factor, Point + // 2) uniform scale factor, x, y + // 3) x scale, y scale, Point + // 4) x scale, y scale, x, y + + switch(arguments.length){ + case 4: + // a and b are scale factor components, c and d are components of a point + return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D + case 3: + if(typeof c == "number"){ + // branch + // a: Number: a uniform scaling factor used for both coordinates + // b: Number: an x component of a central point + // c: Number: a y component of a central point + // d: null + return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: Number: a scaling factor used for the x coordinate + // b: Number: a scaling factor used for the y coordinate + // c: dojox.gfx.Point: a central point + // d: null + return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D + } + // branch + // a: Number: a uniform scaling factor used for both coordinates + // b: dojox.gfx.Point: a central point + // c: null + // d: null + return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D + }, + rotateAt: function(angle, a, b){ + // summary: rotates a picture using a specified point as a center of rotation + // description: Compare with dojox.gfx.matrix.rotate(). + // angle: Number: an angle of rotation in radians (>0 for CW) + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) rotation angle in radians, Point + // 2) rotation angle in radians, x, y + + if(arguments.length > 2){ + return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // angle: Number: an angle of rotation in radians (>0 for CCW) + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + rotategAt: function(degree, a, b){ + // summary: rotates a picture using a specified point as a center of rotation + // description: Compare with dojox.gfx.matrix.rotateg(). + // degree: Number: an angle of rotation in degrees (>0 for CW) + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) rotation angle in degrees, Point + // 2) rotation angle in degrees, x, y + + if(arguments.length > 2){ + return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // degree: Number: an angle of rotation in degrees (>0 for CCW) + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewXAt: function(angle, a, b){ + // summary: skews a picture along the x axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewX(). + // angle: Number: an skewing angle in radians + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) skew angle in radians, Point + // 2) skew angle in radians, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // angle: Number: an skewing angle in radians + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewXgAt: function(degree, a, b){ + // summary: skews a picture along the x axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewXg(). + // degree: Number: an skewing angle in degrees + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) skew angle in degrees, Point + // 2) skew angle in degrees, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // degree: Number: an skewing angle in degrees + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewYAt: function(angle, a, b){ + // summary: skews a picture along the y axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewY(). + // angle: Number: an skewing angle in radians + // a: Number: an x component of a central point + // b: Number: a y component of a central point + + // accepts several signatures: + // 1) skew angle in radians, Point + // 2) skew angle in radians, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // angle: Number: an skewing angle in radians + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D + }, + skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number? */ b){ + // summary: skews a picture along the y axis using a specified point as a center of skewing + // description: Compare with dojox.gfx.matrix.skewYg(). + // degree: Number: an skewing angle in degrees + // a: Number: an x component of a central point + // b: Number?: a y component of a central point + + // accepts several signatures: + // 1) skew angle in degrees, Point + // 2) skew angle in degrees, x, y + + if(arguments.length > 2){ + return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D + } + + // branch + // degree: Number: an skewing angle in degrees + // a: dojox.gfx.Point: a central point + // b: null + return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D + } + + //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions) + + }); + // propagate Matrix2D up + g.Matrix2D = m.Matrix2D; + + return m; +}); + + + +}, +'dojox/charting/plot2d/Scatter':function(){ +define("dojox/charting/plot2d/Scatter", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx", "dojox/gfx/gradutils"], + function(lang, arr, declare, Base, dc, df, dfr, du, fx, gradutils){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Scatter", Base, { + // summary: + // A plot object representing a typical scatter chart. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + shadows: null, // draw shadows + animate: null // animate chart to place + }, + optionalParams: { + // theme component + markerStroke: {}, + markerOutline: {}, + markerShadow: {}, + markerFill: {}, + markerFont: "", + markerFontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create the scatter plot. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs? + // An optional keyword arguments object to help define this plot's parameters. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Scatter + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, events = this.events(); + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(!run.data.length){ + run.dirty = false; + t.skip(); + continue; + } + + var theme = t.next("marker", [this.opt, run]), s = run.group, lpoly, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler); + if(typeof run.data[0] == "number"){ + lpoly = arr.map(run.data, function(v, i){ + return { + x: ht(i + 1) + offsets.l, + y: dim.height - offsets.b - vt(v) + }; + }, this); + }else{ + lpoly = arr.map(run.data, function(v, i){ + return { + x: ht(v.x) + offsets.l, + y: dim.height - offsets.b - vt(v.y) + }; + }, this); + } + + var shadowMarkers = new Array(lpoly.length), + frontMarkers = new Array(lpoly.length), + outlineMarkers = new Array(lpoly.length); + + arr.forEach(lpoly, function(c, i){ + var finalTheme = typeof run.data[i] == "number" ? + t.post(theme, "marker") : + t.addMixin(theme, "marker", run.data[i], true), + path = "M" + c.x + " " + c.y + " " + finalTheme.symbol; + if(finalTheme.marker.shadow){ + shadowMarkers[i] = s.createPath("M" + (c.x + finalTheme.marker.shadow.dx) + " " + + (c.y + finalTheme.marker.shadow.dy) + " " + finalTheme.symbol). + setStroke(finalTheme.marker.shadow).setFill(finalTheme.marker.shadow.color); + if(this.animate){ + this._animateScatter(shadowMarkers[i], dim.height - offsets.b); + } + } + if(finalTheme.marker.outline){ + var outline = dc.makeStroke(finalTheme.marker.outline); + outline.width = 2 * outline.width + finalTheme.marker.stroke.width; + outlineMarkers[i] = s.createPath(path).setStroke(outline); + if(this.animate){ + this._animateScatter(outlineMarkers[i], dim.height - offsets.b); + } + } + var stroke = dc.makeStroke(finalTheme.marker.stroke), + fill = this._plotFill(finalTheme.marker.fill, dim, offsets); + if(fill && (fill.type === "linear" || fill.type == "radial")){ + var color = gradutils.getColor(fill, {x: c.x, y: c.y}); + if(stroke){ + stroke.color = color; + } + frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(color); + }else{ + frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(fill); + } + if(this.animate){ + this._animateScatter(frontMarkers[i], dim.height - offsets.b); + } + }, this); + if(frontMarkers.length){ + run.dyn.stroke = frontMarkers[frontMarkers.length - 1].getStroke(); + run.dyn.fill = frontMarkers[frontMarkers.length - 1].getFill(); + } + + if(events){ + var eventSeries = new Array(frontMarkers.length); + arr.forEach(frontMarkers, function(s, i){ + var o = { + element: "marker", + index: i, + run: run, + shape: s, + outline: outlineMarkers && outlineMarkers[i] || null, + shadow: shadowMarkers && shadowMarkers[i] || null, + cx: lpoly[i].x, + cy: lpoly[i].y + }; + if(typeof run.data[0] == "number"){ + o.x = i + 1; + o.y = run.data[i]; + }else{ + o.x = run.data[i].x; + o.y = run.data[i].y; + } + this._connectEvents(o); + eventSeries[i] = o; + }, this); + this._eventSeries[run.name] = eventSeries; + }else{ + delete this._eventSeries[run.name]; + } + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Scatter + }, + _animateScatter: function(shape, offset){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, offset], end: [0, 0]}, + {name: "scale", start: [0, 0], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); + +}, +'dojox/lang/functional/scan':function(){ +define("dojox/lang/functional/scan", ["dojo/_base/kernel", "dojo/_base/lang", "./lambda"], function(d, darray, df){ + +// This module adds high-level functions and related constructs: +// - "scan" family of functions + +// Notes: +// - missing high-level functions are provided with the compatible API: +// scanl, scanl1, scanr, scanr1 + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument +// - take an iterator objects as the array argument (only scanl, and scanl1) + + var empty = {}; + + d.mixin(df, { + // classic reduce-class functions + scanl: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right using a seed value as a starting point; returns an array + // of values produced by foldl() at that point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var t, n, i; + if(d.isArray(a)){ + // array + t = new Array((n = a.length) + 1); + t[0] = z; + for(i = 0; i < n; z = f.call(o, z, a[i], i, a), t[++i] = z); + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + t = [z]; + for(i = 0; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++, a))); + }else{ + // object/dictionary + t = [z]; + for(i in a){ + if(!(i in empty)){ + t.push(z = f.call(o, z, a[i], i, a)); + } + } + } + return t; // Array + }, + scanl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns an array of values produced by foldl1() at that + // point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var t, n, z, first = true; + if(d.isArray(a)){ + // array + t = new Array(n = a.length); + t[0] = z = a[0]; + for(var i = 1; i < n; t[i] = z = f.call(o, z, a[i], i, a), ++i); + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + if(a.hasNext()){ + t = [z = a.next()]; + for(i = 1; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++, a))); + } + }else{ + // object/dictionary + for(i in a){ + if(!(i in empty)){ + if(first){ + t = [z = a[i]]; + first = false; + }else{ + t.push(z = f.call(o, z, a[i], i, a)); + } + } + } + } + return t; // Array + }, + scanr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left using a seed value as a starting point; returns an array + // of values produced by foldr() at that point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var n = a.length, t = new Array(n + 1), i = n; + t[n] = z; + for(; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z); + return t; // Array + }, + scanr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left; returns an array of values produced by foldr1() at that + // point. + if(typeof a == "string"){ a = a.split(""); } + o = o || d.global; f = df.lambda(f); + var n = a.length, t = new Array(n), z = a[n - 1], i = n - 1; + t[i] = z; + for(; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z); + return t; // Array + } + }); +}); + +}, +'dojox/color/_base':function(){ +define("dojox/color/_base", ["dojo/_base/kernel", "../main", "dojo/_base/lang", "dojo/_base/Color", "dojo/colors"], + function(dojo, dojox, lang, Color, colors){ + +var cx = lang.getObject("dojox.color", true); +/*===== cx = dojox.color =====*/ + +// alias all the dojo.Color mechanisms +cx.Color=Color; +cx.blend=Color.blendColors; +cx.fromRgb=Color.fromRgb; +cx.fromHex=Color.fromHex; +cx.fromArray=Color.fromArray; +cx.fromString=Color.fromString; + +// alias the dojo.colors mechanisms +cx.greyscale=colors.makeGrey; + +lang.mixin(cx,{ + fromCmy: function(/* Object|Array|int */cyan, /*int*/magenta, /*int*/yellow){ + // summary + // Create a dojox.color.Color from a CMY defined color. + // All colors should be expressed as 0-100 (percentage) + + if(lang.isArray(cyan)){ + magenta=cyan[1], yellow=cyan[2], cyan=cyan[0]; + } else if(lang.isObject(cyan)){ + magenta=cyan.m, yellow=cyan.y, cyan=cyan.c; + } + cyan/=100, magenta/=100, yellow/=100; + + var r=1-cyan, g=1-magenta, b=1-yellow; + return new Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color + }, + + fromCmyk: function(/* Object|Array|int */cyan, /*int*/magenta, /*int*/yellow, /*int*/black){ + // summary + // Create a dojox.color.Color from a CMYK defined color. + // All colors should be expressed as 0-100 (percentage) + + if(lang.isArray(cyan)){ + magenta=cyan[1], yellow=cyan[2], black=cyan[3], cyan=cyan[0]; + } else if(lang.isObject(cyan)){ + magenta=cyan.m, yellow=cyan.y, black=cyan.b, cyan=cyan.c; + } + cyan/=100, magenta/=100, yellow/=100, black/=100; + var r,g,b; + r = 1-Math.min(1, cyan*(1-black)+black); + g = 1-Math.min(1, magenta*(1-black)+black); + b = 1-Math.min(1, yellow*(1-black)+black); + return new Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color + }, + + fromHsl: function(/* Object|Array|int */hue, /* int */saturation, /* int */luminosity){ + // summary + // Create a dojox.color.Color from an HSL defined color. + // hue from 0-359 (degrees), saturation and luminosity 0-100. + + if(lang.isArray(hue)){ + saturation=hue[1], luminosity=hue[2], hue=hue[0]; + } else if(lang.isObject(hue)){ + saturation=hue.s, luminosity=hue.l, hue=hue.h; + } + saturation/=100; + luminosity/=100; + + while(hue<0){ hue+=360; } + while(hue>=360){ hue-=360; } + + var r, g, b; + if(hue<120){ + r=(120-hue)/60, g=hue/60, b=0; + } else if (hue<240){ + r=0, g=(240-hue)/60, b=(hue-120)/60; + } else { + r=(hue-240)/60, g=0, b=(360-hue)/60; + } + + r=2*saturation*Math.min(r, 1)+(1-saturation); + g=2*saturation*Math.min(g, 1)+(1-saturation); + b=2*saturation*Math.min(b, 1)+(1-saturation); + if(luminosity<0.5){ + r*=luminosity, g*=luminosity, b*=luminosity; + }else{ + r=(1-luminosity)*r+2*luminosity-1; + g=(1-luminosity)*g+2*luminosity-1; + b=(1-luminosity)*b+2*luminosity-1; + } + return new Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color + } +}); + +cx.fromHsv = function(/* Object|Array|int */hue, /* int */saturation, /* int */value){ + // summary + // Create a dojox.color.Color from an HSV defined color. + // hue from 0-359 (degrees), saturation and value 0-100. + + if(lang.isArray(hue)){ + saturation=hue[1], value=hue[2], hue=hue[0]; + } else if (lang.isObject(hue)){ + saturation=hue.s, value=hue.v, hue=hue.h; + } + + if(hue==360){ hue=0; } + saturation/=100; + value/=100; + + var r, g, b; + if(saturation==0){ + r=value, b=value, g=value; + }else{ + var hTemp=hue/60, i=Math.floor(hTemp), f=hTemp-i; + var p=value*(1-saturation); + var q=value*(1-(saturation*f)); + var t=value*(1-(saturation*(1-f))); + switch(i){ + case 0:{ r=value, g=t, b=p; break; } + case 1:{ r=q, g=value, b=p; break; } + case 2:{ r=p, g=value, b=t; break; } + case 3:{ r=p, g=q, b=value; break; } + case 4:{ r=t, g=p, b=value; break; } + case 5:{ r=value, g=p, b=q; break; } + } + } + return new Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color +}; +lang.extend(Color,{ + toCmy: function(){ + // summary + // Convert this Color to a CMY definition. + var cyan=1-(this.r/255), magenta=1-(this.g/255), yellow=1-(this.b/255); + return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100) }; // Object + }, + + toCmyk: function(){ + // summary + // Convert this Color to a CMYK definition. + var cyan, magenta, yellow, black; + var r=this.r/255, g=this.g/255, b=this.b/255; + black = Math.min(1-r, 1-g, 1-b); + cyan = (1-r-black)/(1-black); + magenta = (1-g-black)/(1-black); + yellow = (1-b-black)/(1-black); + return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100), b:Math.round(black*100) }; // Object + }, + + toHsl: function(){ + // summary + // Convert this Color to an HSL definition. + var r=this.r/255, g=this.g/255, b=this.b/255; + var min = Math.min(r, b, g), max = Math.max(r, g, b); + var delta = max-min; + var h=0, s=0, l=(min+max)/2; + if(l>0 && l<1){ + s = delta/((l<0.5)?(2*l):(2-2*l)); + } + if(delta>0){ + if(max==r && max!=g){ + h+=(g-b)/delta; + } + if(max==g && max!=b){ + h+=(2+(b-r)/delta); + } + if(max==b && max!=r){ + h+=(4+(r-g)/delta); + } + h*=60; + } + return { h:h, s:Math.round(s*100), l:Math.round(l*100) }; // Object + }, + + toHsv: function(){ + // summary + // Convert this Color to an HSV definition. + var r=this.r/255, g=this.g/255, b=this.b/255; + var min = Math.min(r, b, g), max = Math.max(r, g, b); + var delta = max-min; + var h = null, s = (max==0)?0:(delta/max); + if(s==0){ + h = 0; + }else{ + if(r==max){ + h = 60*(g-b)/delta; + }else if(g==max){ + h = 120 + 60*(b-r)/delta; + }else{ + h = 240 + 60*(r-g)/delta; + } + + if(h<0){ h+=360; } + } + return { h:h, s:Math.round(s*100), v:Math.round(max*100) }; // Object + } +}); + +return cx; +}); + +}, +'dojox/charting/plot2d/OHLC':function(){ +define(["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, arr, declare, Base, dc, df, dfr, du, fx){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + // Candlesticks are based on the Bars plot type; we expect the following passed + // as values in a series: + // { x?, open, close, high, low } + // if x is not provided, the array index is used. + // failing to provide the OHLC values will throw an error. + return declare("dojox.charting.plot2d.OHLC", Base, { + // summary: + // A plot that represents typical open/high/low/close (financial reporting, primarily). + // Unlike most charts, the Candlestick expects data points to be represented by + // an object of the form { x?, open, close, high, low, mid? }, where both + // x and mid are optional parameters. If x is not provided, the index of the + // data array is used. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 2, // gap between columns in pixels + animate: null // animate chart to place + }, + optionalParams: { + minBarSize: 1, // minimal bar size in pixels + maxBarSize: 1, // maximal bar size in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a candlestick chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + collectStats: function(series){ + // summary: + // Collect all statistics for drawing this chart. Since the common + // functionality only assumes x and y, OHLC must create it's own + // stats (since data has no y value, but open/close/high/low instead). + // series: dojox.charting.Series[] + // The data series array to be drawn on this plot. + // returns: Object + // Returns an object in the form of { hmin, hmax, vmin, vmax }. + + // we have to roll our own, since we need to use all four passed + // values to figure out our stats, and common only assumes x and y. + var stats = lang.delegate(dc.defaultStats); + for(var i=0; i<series.length; i++){ + var run = series[i]; + if(!run.data.length){ continue; } + var old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, idx){ + if(val !== null){ + var x = val.x || idx + 1; + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low); + stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low); + } + }); + } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + } + return stats; + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = this.collectStats(this.series); + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.OHLC + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("candlestick", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + var finalTheme = t.addMixin(theme, "candlestick", v, true); + + // calculate the points we need for OHLC + var x = ht(v.x || (j+0.5)) + offsets.l + gap, + y = dim.height - offsets.b, + open = vt(v.open), + close = vt(v.close), + high = vt(v.high), + low = vt(v.low); + if(low > high){ + var tmp = high; + high = low; + low = tmp; + } + + if(width >= 1){ + var hl = {x1: width/2, x2: width/2, y1: y - high, y2: y - low}, + op = {x1: 0, x2: ((width/2) + ((finalTheme.series.stroke.width||1)/2)), y1: y-open, y2: y-open}, + cl = {x1: ((width/2) - ((finalTheme.series.stroke.width||1)/2)), x2: width, y1: y-close, y2: y-close}; + var shape = s.createGroup(); + shape.setTransform({dx: x, dy: 0}); + var inner = shape.createGroup(); + inner.createLine(hl).setStroke(finalTheme.series.stroke); + inner.createLine(op).setStroke(finalTheme.series.stroke); + inner.createLine(cl).setStroke(finalTheme.series.stroke); + + // TODO: double check this. + run.dyn.stroke = finalTheme.series.stroke; + if(events){ + var o = { + element: "candlestick", + index: j, + run: run, + shape: inner, + x: x, + y: y-Math.max(open, close), + cx: width/2, + cy: (y-Math.max(open, close)) + (Math.max(open > close ? open-close : close-open, 1)/2), + width: width, + height: Math.max(open > close ? open-close : close-open, 1), + data: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + } + if(this.animate){ + this._animateOHLC(shape, y - low, high - low); + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.OHLC + }, + _animateOHLC: function(shape, voffset, vsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]}, + {name: "scale", start: [1, 1/vsize], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); + +}, +'dojox/charting/plot2d/ClusteredColumns':function(){ +define("dojox/charting/plot2d/ClusteredColumns", ["dojo/_base/array", "dojo/_base/declare", "./Columns", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils"], + function(arr, declare, Columns, dc, df, dfr, du){ +/*===== +var Columns = dojox.charting.plot2d.Columns; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.ClusteredColumns", Columns, { + // summary: + // A plot representing grouped or clustered columns (vertical bars). + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.ClusteredColumns + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, thickness, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt, this.series.length); + gap = f.gap; + width = thickness = f.size; + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i], shift = thickness * i; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("column", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + vv = vt(v), + height = vv - baselineHeight, + h = Math.abs(height), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "column", value, true) : + t.post(theme, "column"); + if(width >= 1 && h >= 0){ + var rect = { + x: offsets.l + ht(j + 0.5) + gap + shift, + y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight), + width: width, height: h + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "column", + index: j, + run: run, + shape: shape, + x: j + 0.5, + y: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.ClusteredColumns + } + }); +}); + +}, +'dojox/charting/Chart':function(){ +define("dojox/charting/Chart", ["dojo/_base/lang", "dojo/_base/array","dojo/_base/declare", "dojo/_base/html", + "dojo/dom", "dojo/dom-geometry", "dojo/dom-construct","dojo/_base/Color", "dojo/_base/sniff", + "./Element", "./Theme", "./Series", "./axis2d/common", + "dojox/gfx", "dojox/lang/functional", "dojox/lang/functional/fold", "dojox/lang/functional/reversed"], + function(lang, arr, declare, html, + dom, domGeom, domConstruct, Color, has, + Element, Theme, Series, common, + g, func, funcFold, funcReversed){ + /*===== + dojox.charting.__ChartCtorArgs = function(margins, stroke, fill, delayInMs){ + // summary: + // The keyword arguments that can be passed in a Chart constructor. + // + // margins: Object? + // Optional margins for the chart, in the form of { l, t, r, b}. + // stroke: dojox.gfx.Stroke? + // An optional outline/stroke for the chart. + // fill: dojox.gfx.Fill? + // An optional fill for the chart. + // delayInMs: Number + // Delay in ms for delayedRender(). Default: 200. + this.margins = margins; + this.stroke = stroke; + this.fill = fill; + this.delayInMs = delayInMs; + } + =====*/ + var dc = dojox.charting, + clear = func.lambda("item.clear()"), + purge = func.lambda("item.purgeGroup()"), + destroy = func.lambda("item.destroy()"), + makeClean = func.lambda("item.dirty = false"), + makeDirty = func.lambda("item.dirty = true"), + getName = func.lambda("item.name"); + + declare("dojox.charting.Chart", null, { + // summary: + // The main chart object in dojox.charting. This will create a two dimensional + // chart based on dojox.gfx. + // + // description: + // dojox.charting.Chart is the primary object used for any kind of charts. It + // is simple to create--just pass it a node reference, which is used as the + // container for the chart--and a set of optional keyword arguments and go. + // + // Note that like most of dojox.gfx, most of dojox.charting.Chart's methods are + // designed to return a reference to the chart itself, to allow for functional + // chaining. This makes defining everything on a Chart very easy to do. + // + // example: + // Create an area chart, with smoothing. + // | new dojox.charting.Chart(node)) + // | .addPlot("default", { type: "Areas", tension: "X" }) + // | .setTheme(dojox.charting.themes.Shrooms) + // | .addSeries("Series A", [1, 2, 0.5, 1.5, 1, 2.8, 0.4]) + // | .addSeries("Series B", [2.6, 1.8, 2, 1, 1.4, 0.7, 2]) + // | .addSeries("Series C", [6.3, 1.8, 3, 0.5, 4.4, 2.7, 2]) + // | .render(); + // + // example: + // The form of data in a data series can take a number of forms: a simple array, + // an array of objects {x,y}, or something custom (as determined by the plot). + // Here's an example of a Candlestick chart, which expects an object of + // { open, high, low, close }. + // | new dojox.charting.Chart(node)) + // | .addPlot("default", {type: "Candlesticks", gap: 1}) + // | .addAxis("x", {fixLower: "major", fixUpper: "major", includeZero: true}) + // | .addAxis("y", {vertical: true, fixLower: "major", fixUpper: "major", natural: true}) + // | .addSeries("Series A", [ + // | { open: 20, close: 16, high: 22, low: 8 }, + // | { open: 16, close: 22, high: 26, low: 6, mid: 18 }, + // | { open: 22, close: 18, high: 22, low: 11, mid: 21 }, + // | { open: 18, close: 29, high: 32, low: 14, mid: 27 }, + // | { open: 29, close: 24, high: 29, low: 13, mid: 27 }, + // | { open: 24, close: 8, high: 24, low: 5 }, + // | { open: 8, close: 16, high: 22, low: 2 }, + // | { open: 16, close: 12, high: 19, low: 7 }, + // | { open: 12, close: 20, high: 22, low: 8 }, + // | { open: 20, close: 16, high: 22, low: 8 }, + // | { open: 16, close: 22, high: 26, low: 6, mid: 18 }, + // | { open: 22, close: 18, high: 22, low: 11, mid: 21 }, + // | { open: 18, close: 29, high: 32, low: 14, mid: 27 }, + // | { open: 29, close: 24, high: 29, low: 13, mid: 27 }, + // | { open: 24, close: 8, high: 24, low: 5 }, + // | { open: 8, close: 16, high: 22, low: 2 }, + // | { open: 16, close: 12, high: 19, low: 7 }, + // | { open: 12, close: 20, high: 22, low: 8 }, + // | { open: 20, close: 16, high: 22, low: 8 }, + // | { open: 16, close: 22, high: 26, low: 6 }, + // | { open: 22, close: 18, high: 22, low: 11 }, + // | { open: 18, close: 29, high: 32, low: 14 }, + // | { open: 29, close: 24, high: 29, low: 13 }, + // | { open: 24, close: 8, high: 24, low: 5 }, + // | { open: 8, close: 16, high: 22, low: 2 }, + // | { open: 16, close: 12, high: 19, low: 7 }, + // | { open: 12, close: 20, high: 22, low: 8 }, + // | { open: 20, close: 16, high: 22, low: 8 } + // | ], + // | { stroke: { color: "green" }, fill: "lightgreen" } + // | ) + // | .render(); + + // theme: dojox.charting.Theme? + // An optional theme to use for styling the chart. + // axes: dojox.charting.Axis{}? + // A map of axes for use in plotting a chart. + // stack: dojox.charting.plot2d.Base[] + // A stack of plotters. + // plots: dojox.charting.plot2d.Base{} + // A map of plotter indices + // series: dojox.charting.Series[] + // The stack of data runs used to create plots. + // runs: dojox.charting.Series{} + // A map of series indices + // margins: Object? + // The margins around the chart. Default is { l:10, t:10, r:10, b:10 }. + // stroke: dojox.gfx.Stroke? + // The outline of the chart (stroke in vector graphics terms). + // fill: dojox.gfx.Fill? + // The color for the chart. + // node: DOMNode + // The container node passed to the constructor. + // surface: dojox.gfx.Surface + // The main graphics surface upon which a chart is drawn. + // dirty: Boolean + // A boolean flag indicating whether or not the chart needs to be updated/re-rendered. + // coords: Object + // The coordinates on a page of the containing node, as returned from dojo.coords. + + constructor: function(/* DOMNode */node, /* dojox.charting.__ChartCtorArgs? */kwArgs){ + // summary: + // The constructor for a new Chart. Initializes all parameters used for a chart. + // returns: dojox.charting.Chart + // The newly created chart. + + // initialize parameters + if(!kwArgs){ kwArgs = {}; } + this.margins = kwArgs.margins ? kwArgs.margins : {l: 10, t: 10, r: 10, b: 10}; + this.stroke = kwArgs.stroke; + this.fill = kwArgs.fill; + this.delayInMs = kwArgs.delayInMs || 200; + this.title = kwArgs.title; + this.titleGap = kwArgs.titleGap; + this.titlePos = kwArgs.titlePos; + this.titleFont = kwArgs.titleFont; + this.titleFontColor = kwArgs.titleFontColor; + this.chartTitle = null; + + // default initialization + this.theme = null; + this.axes = {}; // map of axes + this.stack = []; // stack of plotters + this.plots = {}; // map of plotter indices + this.series = []; // stack of data runs + this.runs = {}; // map of data run indices + this.dirty = true; + this.coords = null; + + // create a surface + this.node = dom.byId(node); + var box = domGeom.getMarginBox(node); + this.surface = g.createSurface(this.node, box.w || 400, box.h || 300); + }, + destroy: function(){ + // summary: + // Cleanup when a chart is to be destroyed. + // returns: void + arr.forEach(this.series, destroy); + arr.forEach(this.stack, destroy); + func.forIn(this.axes, destroy); + if(this.chartTitle && this.chartTitle.tagName){ + // destroy title if it is a DOM node + domConstruct.destroy(this.chartTitle); + } + this.surface.destroy(); + }, + getCoords: function(){ + // summary: + // Get the coordinates and dimensions of the containing DOMNode, as + // returned by dojo.coords. + // returns: Object + // The resulting coordinates of the chart. See dojo.coords for details. + return html.coords(this.node, true); // Object + }, + setTheme: function(theme){ + // summary: + // Set a theme of the chart. + // theme: dojox.charting.Theme + // The theme to be used for visual rendering. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + this.theme = theme.clone(); + this.dirty = true; + return this; // dojox.charting.Chart + }, + addAxis: function(name, kwArgs){ + // summary: + // Add an axis to the chart, for rendering. + // name: String + // The name of the axis. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // An optional keyword arguments object for use in defining details of an axis. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var axis, axisType = kwArgs && kwArgs.type || "Default"; + if(typeof axisType == "string"){ + if(!dc.axis2d || !dc.axis2d[axisType]){ + throw Error("Can't find axis: " + axisType + " - Check " + "require() dependencies."); + } + axis = new dc.axis2d[axisType](this, kwArgs); + }else{ + axis = new axisType(this, kwArgs); + } + axis.name = name; + axis.dirty = true; + if(name in this.axes){ + this.axes[name].destroy(); + } + this.axes[name] = axis; + this.dirty = true; + return this; // dojox.charting.Chart + }, + getAxis: function(name){ + // summary: + // Get the given axis, by name. + // name: String + // The name the axis was defined by. + // returns: dojox.charting.axis2d.Default + // The axis as stored in the chart's axis map. + return this.axes[name]; // dojox.charting.axis2d.Default + }, + removeAxis: function(name){ + // summary: + // Remove the axis that was defined using name. + // name: String + // The axis name, as defined in addAxis. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.axes){ + // destroy the axis + this.axes[name].destroy(); + delete this.axes[name]; + // mark the chart as dirty + this.dirty = true; + } + return this; // dojox.charting.Chart + }, + addPlot: function(name, kwArgs){ + // summary: + // Add a new plot to the chart, defined by name and using the optional keyword arguments object. + // Note that dojox.charting assumes the main plot to be called "default"; if you do not have + // a plot called "default" and attempt to add data series to the chart without specifying the + // plot to be rendered on, you WILL get errors. + // name: String + // The name of the plot to be added to the chart. If you only plan on using one plot, call it "default". + // kwArgs: dojox.charting.plot2d.__PlotCtorArgs + // An object with optional parameters for the plot in question. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var plot, plotType = kwArgs && kwArgs.type || "Default"; + if(typeof plotType == "string"){ + if(!dc.plot2d || !dc.plot2d[plotType]){ + throw Error("Can't find plot: " + plotType + " - didn't you forget to dojo" + ".require() it?"); + } + plot = new dc.plot2d[plotType](this, kwArgs); + }else{ + plot = new plotType(this, kwArgs); + } + plot.name = name; + plot.dirty = true; + if(name in this.plots){ + this.stack[this.plots[name]].destroy(); + this.stack[this.plots[name]] = plot; + }else{ + this.plots[name] = this.stack.length; + this.stack.push(plot); + } + this.dirty = true; + return this; // dojox.charting.Chart + }, + getPlot: function(name){ + // summary: + // Get the given plot, by name. + // name: String + // The name the plot was defined by. + // returns: dojox.charting.plot2d.Base + // The plot. + return this.stack[this.plots[name]]; + }, + removePlot: function(name){ + // summary: + // Remove the plot defined using name from the chart's plot stack. + // name: String + // The name of the plot as defined using addPlot. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.plots){ + // get the index and remove the name + var index = this.plots[name]; + delete this.plots[name]; + // destroy the plot + this.stack[index].destroy(); + // remove the plot from the stack + this.stack.splice(index, 1); + // update indices to reflect the shift + func.forIn(this.plots, function(idx, name, plots){ + if(idx > index){ + plots[name] = idx - 1; + } + }); + // remove all related series + var ns = arr.filter(this.series, function(run){ return run.plot != name; }); + if(ns.length < this.series.length){ + // kill all removed series + arr.forEach(this.series, function(run){ + if(run.plot == name){ + run.destroy(); + } + }); + // rebuild all necessary data structures + this.runs = {}; + arr.forEach(ns, function(run, index){ + this.runs[run.plot] = index; + }, this); + this.series = ns; + } + // mark the chart as dirty + this.dirty = true; + } + return this; // dojox.charting.Chart + }, + getPlotOrder: function(){ + // summary: + // Returns an array of plot names in the current order + // (the top-most plot is the first). + // returns: Array + return func.map(this.stack, getName); // Array + }, + setPlotOrder: function(newOrder){ + // summary: + // Sets new order of plots. newOrder cannot add or remove + // plots. Wrong names, or dups are ignored. + // newOrder: Array: + // Array of plot names compatible with getPlotOrder(). + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var names = {}, + order = func.filter(newOrder, function(name){ + if(!(name in this.plots) || (name in names)){ + return false; + } + names[name] = 1; + return true; + }, this); + if(order.length < this.stack.length){ + func.forEach(this.stack, function(plot){ + var name = plot.name; + if(!(name in names)){ + order.push(name); + } + }); + } + var newStack = func.map(order, function(name){ + return this.stack[this.plots[name]]; + }, this); + func.forEach(newStack, function(plot, i){ + this.plots[plot.name] = i; + }, this); + this.stack = newStack; + this.dirty = true; + return this; // dojox.charting.Chart + }, + movePlotToFront: function(name){ + // summary: + // Moves a given plot to front. + // name: String: + // Plot's name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.plots){ + var index = this.plots[name]; + if(index){ + var newOrder = this.getPlotOrder(); + newOrder.splice(index, 1); + newOrder.unshift(name); + return this.setPlotOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + movePlotToBack: function(name){ + // summary: + // Moves a given plot to back. + // name: String: + // Plot's name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.plots){ + var index = this.plots[name]; + if(index < this.stack.length - 1){ + var newOrder = this.getPlotOrder(); + newOrder.splice(index, 1); + newOrder.push(name); + return this.setPlotOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + addSeries: function(name, data, kwArgs){ + // summary: + // Add a data series to the chart for rendering. + // name: String: + // The name of the data series to be plotted. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + // kwArgs: dojox.charting.__SeriesCtorArgs?: + // An optional keyword arguments object that will be mixed into + // the resultant series object. + // returns: dojox.charting.Chart: + // A reference to the current chart for functional chaining. + var run = new Series(this, data, kwArgs); + run.name = name; + if(name in this.runs){ + this.series[this.runs[name]].destroy(); + this.series[this.runs[name]] = run; + }else{ + this.runs[name] = this.series.length; + this.series.push(run); + } + this.dirty = true; + // fix min/max + if(!("ymin" in run) && "min" in run){ run.ymin = run.min; } + if(!("ymax" in run) && "max" in run){ run.ymax = run.max; } + return this; // dojox.charting.Chart + }, + getSeries: function(name){ + // summary: + // Get the given series, by name. + // name: String + // The name the series was defined by. + // returns: dojox.charting.Series + // The series. + return this.series[this.runs[name]]; + }, + removeSeries: function(name){ + // summary: + // Remove the series defined by name from the chart. + // name: String + // The name of the series as defined by addSeries. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + // get the index and remove the name + var index = this.runs[name]; + delete this.runs[name]; + // destroy the run + this.series[index].destroy(); + // remove the run from the stack of series + this.series.splice(index, 1); + // update indices to reflect the shift + func.forIn(this.runs, function(idx, name, runs){ + if(idx > index){ + runs[name] = idx - 1; + } + }); + this.dirty = true; + } + return this; // dojox.charting.Chart + }, + updateSeries: function(name, data){ + // summary: + // Update the given series with a new set of data points. + // name: String + // The name of the series as defined in addSeries. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + var run = this.series[this.runs[name]]; + run.update(data); + this._invalidateDependentPlots(run.plot, false); + this._invalidateDependentPlots(run.plot, true); + } + return this; // dojox.charting.Chart + }, + getSeriesOrder: function(plotName){ + // summary: + // Returns an array of series names in the current order + // (the top-most series is the first) within a plot. + // plotName: String: + // Plot's name. + // returns: Array + return func.map(func.filter(this.series, function(run){ + return run.plot == plotName; + }), getName); + }, + setSeriesOrder: function(newOrder){ + // summary: + // Sets new order of series within a plot. newOrder cannot add + // or remove series. Wrong names, or dups are ignored. + // newOrder: Array: + // Array of series names compatible with getPlotOrder(). All + // series should belong to the same plot. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var plotName, names = {}, + order = func.filter(newOrder, function(name){ + if(!(name in this.runs) || (name in names)){ + return false; + } + var run = this.series[this.runs[name]]; + if(plotName){ + if(run.plot != plotName){ + return false; + } + }else{ + plotName = run.plot; + } + names[name] = 1; + return true; + }, this); + func.forEach(this.series, function(run){ + var name = run.name; + if(!(name in names) && run.plot == plotName){ + order.push(name); + } + }); + var newSeries = func.map(order, function(name){ + return this.series[this.runs[name]]; + }, this); + this.series = newSeries.concat(func.filter(this.series, function(run){ + return run.plot != plotName; + })); + func.forEach(this.series, function(run, i){ + this.runs[run.name] = i; + }, this); + this.dirty = true; + return this; // dojox.charting.Chart + }, + moveSeriesToFront: function(name){ + // summary: + // Moves a given series to front of a plot. + // name: String: + // Series' name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + var index = this.runs[name], + newOrder = this.getSeriesOrder(this.series[index].plot); + if(name != newOrder[0]){ + newOrder.splice(index, 1); + newOrder.unshift(name); + return this.setSeriesOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + moveSeriesToBack: function(name){ + // summary: + // Moves a given series to back of a plot. + // name: String: + // Series' name to move. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(name in this.runs){ + var index = this.runs[name], + newOrder = this.getSeriesOrder(this.series[index].plot); + if(name != newOrder[newOrder.length - 1]){ + newOrder.splice(index, 1); + newOrder.push(name); + return this.setSeriesOrder(newOrder); // dojox.charting.Chart + } + } + return this; // dojox.charting.Chart + }, + resize: function(width, height){ + // summary: + // Resize the chart to the dimensions of width and height. + // description: + // Resize the chart and its surface to the width and height dimensions. + // If no width/height or box is provided, resize the surface to the marginBox of the chart. + // width: Number + // The new width of the chart. + // height: Number + // The new height of the chart. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var box; + switch(arguments.length){ + // case 0, do not resize the div, just the surface + case 1: + // argument, override node box + box = lang.mixin({}, width); + domGeom.setMarginBox(this.node, box); + break; + case 2: + box = {w: width, h: height}; + // argument, override node box + domGeom.setMarginBox(this.node, box); + break; + } + // in all cases take back the computed box + box = domGeom.getMarginBox(this.node); + var d = this.surface.getDimensions(); + if(d.width != box.w || d.height != box.h){ + // and set it on the surface + this.surface.setDimensions(box.w, box.h); + this.dirty = true; + return this.render(); // dojox.charting.Chart + }else{ + return this; + } + }, + getGeometry: function(){ + // summary: + // Returns a map of information about all axes in a chart and what they represent + // in terms of scaling (see dojox.charting.axis2d.Default.getScaler). + // returns: Object + // An map of geometry objects, a one-to-one mapping of axes. + var ret = {}; + func.forIn(this.axes, function(axis){ + if(axis.initialized()){ + ret[axis.name] = { + name: axis.name, + vertical: axis.vertical, + scaler: axis.scaler, + ticks: axis.ticks + }; + } + }); + return ret; // Object + }, + setAxisWindow: function(name, scale, offset, zoom){ + // summary: + // Zooms an axis and all dependent plots. Can be used to zoom in 1D. + // name: String + // The name of the axis as defined by addAxis. + // scale: Number + // The scale on the target axis. + // offset: Number + // Any offest, as measured by axis tick + // zoom: Boolean|Object? + // The chart zooming animation trigger. This is null by default, + // e.g. {duration: 1200}, or just set true. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + var axis = this.axes[name]; + if(axis){ + axis.setWindow(scale, offset); + arr.forEach(this.stack,function(plot){ + if(plot.hAxis == name || plot.vAxis == name){ + plot.zoom = zoom; + } + }); + } + return this; // dojox.charting.Chart + }, + setWindow: function(sx, sy, dx, dy, zoom){ + // summary: + // Zooms in or out any plots in two dimensions. + // sx: Number + // The scale for the x axis. + // sy: Number + // The scale for the y axis. + // dx: Number + // The pixel offset on the x axis. + // dy: Number + // The pixel offset on the y axis. + // zoom: Boolean|Object? + // The chart zooming animation trigger. This is null by default, + // e.g. {duration: 1200}, or just set true. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(!("plotArea" in this)){ + this.calculateGeometry(); + } + func.forIn(this.axes, function(axis){ + var scale, offset, bounds = axis.getScaler().bounds, + s = bounds.span / (bounds.upper - bounds.lower); + if(axis.vertical){ + scale = sy; + offset = dy / s / scale; + }else{ + scale = sx; + offset = dx / s / scale; + } + axis.setWindow(scale, offset); + }); + arr.forEach(this.stack, function(plot){ plot.zoom = zoom; }); + return this; // dojox.charting.Chart + }, + zoomIn: function(name, range){ + // summary: + // Zoom the chart to a specific range on one axis. This calls render() + // directly as a convenience method. + // name: String + // The name of the axis as defined by addAxis. + // range: Array + // The end points of the zoom range, measured in axis ticks. + var axis = this.axes[name]; + if(axis){ + var scale, offset, bounds = axis.getScaler().bounds; + var lower = Math.min(range[0],range[1]); + var upper = Math.max(range[0],range[1]); + lower = range[0] < bounds.lower ? bounds.lower : lower; + upper = range[1] > bounds.upper ? bounds.upper : upper; + scale = (bounds.upper - bounds.lower) / (upper - lower); + offset = lower - bounds.lower; + this.setAxisWindow(name, scale, offset); + this.render(); + } + }, + calculateGeometry: function(){ + // summary: + // Calculate the geometry of the chart based on the defined axes of + // a chart. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(this.dirty){ + return this.fullGeometry(); + } + + // calculate geometry + var dirty = arr.filter(this.stack, function(plot){ + return plot.dirty || + (plot.hAxis && this.axes[plot.hAxis].dirty) || + (plot.vAxis && this.axes[plot.vAxis].dirty); + }, this); + calculateAxes(dirty, this.plotArea); + + return this; // dojox.charting.Chart + }, + fullGeometry: function(){ + // summary: + // Calculate the full geometry of the chart. This includes passing + // over all major elements of a chart (plots, axes, series, container) + // in order to ensure proper rendering. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + this._makeDirty(); + + // clear old values + arr.forEach(this.stack, clear); + + // rebuild new connections, and add defaults + + // set up a theme + if(!this.theme){ + this.setTheme(new Theme(dojox.charting._def)); + } + + // assign series + arr.forEach(this.series, function(run){ + if(!(run.plot in this.plots)){ + if(!dc.plot2d || !dc.plot2d.Default){ + throw Error("Can't find plot: Default - didn't you forget to dojo" + ".require() it?"); + } + var plot = new dc.plot2d.Default(this, {}); + plot.name = run.plot; + this.plots[run.plot] = this.stack.length; + this.stack.push(plot); + } + this.stack[this.plots[run.plot]].addSeries(run); + }, this); + // assign axes + arr.forEach(this.stack, function(plot){ + if(plot.hAxis){ + plot.setAxis(this.axes[plot.hAxis]); + } + if(plot.vAxis){ + plot.setAxis(this.axes[plot.vAxis]); + } + }, this); + + // calculate geometry + + // 1st pass + var dim = this.dim = this.surface.getDimensions(); + dim.width = g.normalizedLength(dim.width); + dim.height = g.normalizedLength(dim.height); + func.forIn(this.axes, clear); + calculateAxes(this.stack, dim); + + // assumption: we don't have stacked axes yet + var offsets = this.offsets = { l: 0, r: 0, t: 0, b: 0 }; + func.forIn(this.axes, function(axis){ + func.forIn(axis.getOffsets(), function(o, i){ offsets[i] += o; }); + }); + // add title area + if(this.title){ + this.titleGap = (this.titleGap==0) ? 0 : this.titleGap || this.theme.chart.titleGap || 20; + this.titlePos = this.titlePos || this.theme.chart.titlePos || "top"; + this.titleFont = this.titleFont || this.theme.chart.titleFont; + this.titleFontColor = this.titleFontColor || this.theme.chart.titleFontColor || "black"; + var tsize = g.normalizedLength(g.splitFontString(this.titleFont).size); + offsets[this.titlePos=="top" ? "t":"b"] += (tsize + this.titleGap); + } + // add margins + func.forIn(this.margins, function(o, i){ offsets[i] += o; }); + + // 2nd pass with realistic dimensions + this.plotArea = { + width: dim.width - offsets.l - offsets.r, + height: dim.height - offsets.t - offsets.b + }; + func.forIn(this.axes, clear); + calculateAxes(this.stack, this.plotArea); + + return this; // dojox.charting.Chart + }, + render: function(){ + // summary: + // Render the chart according to the current information defined. This should + // be the last call made when defining/creating a chart, or if data within the + // chart has been changed. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(this.theme){ + this.theme.clear(); + } + + if(this.dirty){ + return this.fullRender(); + } + + this.calculateGeometry(); + + // go over the stack backwards + func.forEachRev(this.stack, function(plot){ plot.render(this.dim, this.offsets); }, this); + + // go over axes + func.forIn(this.axes, function(axis){ axis.render(this.dim, this.offsets); }, this); + + this._makeClean(); + + // BEGIN FOR HTML CANVAS + if(this.surface.render){ this.surface.render(); }; + // END FOR HTML CANVAS + + return this; // dojox.charting.Chart + }, + fullRender: function(){ + // summary: + // Force a full rendering of the chart, including full resets on the chart itself. + // You should not call this method directly unless absolutely necessary. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + + // calculate geometry + this.fullGeometry(); + var offsets = this.offsets, dim = this.dim, rect; + + // get required colors + //var requiredColors = func.foldl(this.stack, "z + plot.getRequiredColors()", 0); + //this.theme.defineColors({num: requiredColors, cache: false}); + + // clear old shapes + arr.forEach(this.series, purge); + func.forIn(this.axes, purge); + arr.forEach(this.stack, purge); + if(this.chartTitle && this.chartTitle.tagName){ + // destroy title if it is a DOM node + domConstruct.destroy(this.chartTitle); + } + this.surface.clear(); + this.chartTitle = null; + + // generate shapes + + // draw a plot background + var t = this.theme, + fill = t.plotarea && t.plotarea.fill, + stroke = t.plotarea && t.plotarea.stroke, + // size might be neg if offsets are bigger that chart size this happens quite often at + // initialization time if the chart widget is used in a BorderContainer + // this will fail on IE/VML + w = Math.max(0, dim.width - offsets.l - offsets.r), + h = Math.max(0, dim.height - offsets.t - offsets.b), + rect = { + x: offsets.l - 1, y: offsets.t - 1, + width: w + 2, + height: h + 2 + }; + if(fill){ + fill = Element.prototype._shapeFill(Element.prototype._plotFill(fill, dim, offsets), rect); + this.surface.createRect(rect).setFill(fill); + } + if(stroke){ + this.surface.createRect({ + x: offsets.l, y: offsets.t, + width: w + 1, + height: h + 1 + }).setStroke(stroke); + } + + // go over the stack backwards + func.foldr(this.stack, function(z, plot){ return plot.render(dim, offsets), 0; }, 0); + + // pseudo-clipping: matting + fill = this.fill !== undefined ? this.fill : (t.chart && t.chart.fill); + stroke = this.stroke !== undefined ? this.stroke : (t.chart && t.chart.stroke); + + // TRT: support for "inherit" as a named value in a theme. + if(fill == "inherit"){ + // find the background color of the nearest ancestor node, and use that explicitly. + var node = this.node, fill = new Color(html.style(node, "backgroundColor")); + while(fill.a==0 && node!=document.documentElement){ + fill = new Color(html.style(node, "backgroundColor")); + node = node.parentNode; + } + } + + if(fill){ + fill = Element.prototype._plotFill(fill, dim, offsets); + if(offsets.l){ // left + rect = { + width: offsets.l, + height: dim.height + 1 + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + if(offsets.r){ // right + rect = { + x: dim.width - offsets.r, + width: offsets.r + 1, + height: dim.height + 2 + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + if(offsets.t){ // top + rect = { + width: dim.width + 1, + height: offsets.t + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + if(offsets.b){ // bottom + rect = { + y: dim.height - offsets.b, + width: dim.width + 1, + height: offsets.b + 2 + }; + this.surface.createRect(rect).setFill(Element.prototype._shapeFill(fill, rect)); + } + } + if(stroke){ + this.surface.createRect({ + width: dim.width - 1, + height: dim.height - 1 + }).setStroke(stroke); + } + + //create title: Whether to make chart title as a widget which extends dojox.charting.Element? + if(this.title){ + var forceHtmlLabels = (g.renderer == "canvas"), + labelType = forceHtmlLabels || !has("ie") && !has("opera") ? "html" : "gfx", + tsize = g.normalizedLength(g.splitFontString(this.titleFont).size); + this.chartTitle = common.createText[labelType]( + this, + this.surface, + dim.width/2, + this.titlePos=="top" ? tsize + this.margins.t : dim.height - this.margins.b, + "middle", + this.title, + this.titleFont, + this.titleFontColor + ); + } + + // go over axes + func.forIn(this.axes, function(axis){ axis.render(dim, offsets); }); + + this._makeClean(); + + // BEGIN FOR HTML CANVAS + if(this.surface.render){ this.surface.render(); }; + // END FOR HTML CANVAS + + return this; // dojox.charting.Chart + }, + delayedRender: function(){ + // summary: + // Delayed render, which is used to collect multiple updates + // within a delayInMs time window. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + + if(!this._delayedRenderHandle){ + this._delayedRenderHandle = setTimeout( + lang.hitch(this, function(){ + clearTimeout(this._delayedRenderHandle); + this._delayedRenderHandle = null; + this.render(); + }), + this.delayInMs + ); + } + + return this; // dojox.charting.Chart + }, + connectToPlot: function(name, object, method){ + // summary: + // A convenience method to connect a function to a plot. + // name: String + // The name of the plot as defined by addPlot. + // object: Object + // The object to be connected. + // method: Function + // The function to be executed. + // returns: Array + // A handle to the connection, as defined by dojo.connect (see dojo.connect). + return name in this.plots ? this.stack[this.plots[name]].connect(object, method) : null; // Array + }, + fireEvent: function(seriesName, eventName, index){ + // summary: + // Fires a synthetic event for a series item. + // seriesName: String: + // Series name. + // eventName: String: + // Event name to simulate: onmouseover, onmouseout, onclick. + // index: Number: + // Valid data value index for the event. + // returns: dojox.charting.Chart + // A reference to the current chart for functional chaining. + if(seriesName in this.runs){ + var plotName = this.series[this.runs[seriesName]].plot; + if(plotName in this.plots){ + var plot = this.stack[this.plots[plotName]]; + if(plot){ + plot.fireEvent(seriesName, eventName, index); + } + } + } + return this; // dojox.charting.Chart + }, + _makeClean: function(){ + // reset dirty flags + arr.forEach(this.axes, makeClean); + arr.forEach(this.stack, makeClean); + arr.forEach(this.series, makeClean); + this.dirty = false; + }, + _makeDirty: function(){ + // reset dirty flags + arr.forEach(this.axes, makeDirty); + arr.forEach(this.stack, makeDirty); + arr.forEach(this.series, makeDirty); + this.dirty = true; + }, + _invalidateDependentPlots: function(plotName, /* Boolean */ verticalAxis){ + if(plotName in this.plots){ + var plot = this.stack[this.plots[plotName]], axis, + axisName = verticalAxis ? "vAxis" : "hAxis"; + if(plot[axisName]){ + axis = this.axes[plot[axisName]]; + if(axis && axis.dependOnData()){ + axis.dirty = true; + // find all plots and mark them dirty + arr.forEach(this.stack, function(p){ + if(p[axisName] && p[axisName] == plot[axisName]){ + p.dirty = true; + } + }); + } + }else{ + plot.dirty = true; + } + } + } + }); + + function hSection(stats){ + return {min: stats.hmin, max: stats.hmax}; + } + + function vSection(stats){ + return {min: stats.vmin, max: stats.vmax}; + } + + function hReplace(stats, h){ + stats.hmin = h.min; + stats.hmax = h.max; + } + + function vReplace(stats, v){ + stats.vmin = v.min; + stats.vmax = v.max; + } + + function combineStats(target, source){ + if(target && source){ + target.min = Math.min(target.min, source.min); + target.max = Math.max(target.max, source.max); + } + return target || source; + } + + function calculateAxes(stack, plotArea){ + var plots = {}, axes = {}; + arr.forEach(stack, function(plot){ + var stats = plots[plot.name] = plot.getSeriesStats(); + if(plot.hAxis){ + axes[plot.hAxis] = combineStats(axes[plot.hAxis], hSection(stats)); + } + if(plot.vAxis){ + axes[plot.vAxis] = combineStats(axes[plot.vAxis], vSection(stats)); + } + }); + arr.forEach(stack, function(plot){ + var stats = plots[plot.name]; + if(plot.hAxis){ + hReplace(stats, axes[plot.hAxis]); + } + if(plot.vAxis){ + vReplace(stats, axes[plot.vAxis]); + } + plot.initializeScalers(plotArea, stats); + }); + } + + return dojox.charting.Chart; +}); + +}, +'dojox/lang/functional/sequence':function(){ +define("dojox/lang/functional/sequence", ["dojo/_base/lang", "./lambda"], function(lang, df){ + +// This module adds high-level functions and related constructs: +// - sequence generators + +// If you want more general sequence builders check out listcomp.js and +// unfold() (in fold.js). + +// Defined methods: +// - take any valid lambda argument as the functional argument + +/*===== + var df = dojox.lang.functional; + =====*/ + + lang.mixin(df, { + // sequence generators + repeat: function(/*Number*/ n, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: builds an array by repeatedly applying a unary function N times + // with a seed value Z. N should be greater than 0. + o = o || dojo.global; f = df.lambda(f); + var t = new Array(n), i = 1; + t[0] = z; + for(; i < n; t[i] = z = f.call(o, z), ++i); + return t; // Array + }, + until: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: builds an array by repeatedly applying a unary function with + // a seed value Z until the predicate is satisfied. + o = o || dojo.global; f = df.lambda(f); pr = df.lambda(pr); + var t = []; + for(; !pr.call(o, z); t.push(z), z = f.call(o, z)); + return t; // Array + } + }); + + return df; +}); + +}, +'dojox/charting/plot2d/MarkersOnly':function(){ +define("dojox/charting/plot2d/MarkersOnly", ["dojo/_base/declare", "./Default"], function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + return declare("dojox.charting.plot2d.MarkersOnly", Default, { + // summary: + // A convenience object to draw only markers (like a scatter but not quite). + constructor: function(){ + // summary: + // Set up our default plot to only have markers and no lines. + this.opt.lines = false; + this.opt.markers = true; + } + }); +}); + +}, +'dojox/charting/plot2d/Areas':function(){ +define("dojox/charting/plot2d/Areas", ["dojo/_base/declare", "./Default"], + function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + return declare("dojox.charting.plot2d.Areas", Default, { + // summary: + // Represents an area chart. See dojox.charting.plot2d.Default for details. + constructor: function(){ + this.opt.lines = true; + this.opt.areas = true; + } + }); +}); + +}, +'dojox/charting/action2d/Base':function(){ +define("dojox/charting/action2d/Base", ["dojo/_base/lang", "dojo/_base/declare"], + function(lang, declare){ + + return declare("dojox.charting.action2d.Base", null, { + // summary: + // Base action class for plot and chart actions. + + constructor: function(chart, plot){ + // summary: + // Create a new base action. This can either be a plot or a chart action. + // chart: dojox.charting.Chart + // The chart this action applies to. + // plot: String?|dojox.charting.plot2d.Base? + // Optional target plot for this action. Default is "default". + this.chart = chart; + this.plot = plot ? (lang.isString(plot) ? this.chart.getPlot(plot) : plot) : this.chart.getPlot("default"); + }, + + connect: function(){ + // summary: + // Connect this action to the plot or the chart. + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the plot or the chart. + }, + + destroy: function(){ + // summary: + // Do any cleanup needed when destroying parent elements. + this.disconnect(); + } + }); + +}); + +}, +'dojo/fx':function(){ +define([ + "./_base/lang", + "./Evented", + "./_base/kernel", + "./_base/array", + "./_base/connect", + "./_base/fx", + "./dom", + "./dom-style", + "./dom-geometry", + "./ready", + "require" // for context sensitive loading of Toggler +], function(lang, Evented, dojo, arrayUtil, connect, baseFx, dom, domStyle, geom, ready, require) { + + // module: + // dojo/fx + // summary: + // TODOC + + + /*===== + dojo.fx = { + // summary: Effects library on top of Base animations + }; + var coreFx = dojo.fx; + =====*/ + +// For back-compat, remove in 2.0. +if(!dojo.isAsync){ + ready(0, function(){ + var requires = ["./fx/Toggler"]; + require(requires); // use indirection so modules not rolled into a build + }); +} + + var coreFx = dojo.fx = {}; + + var _baseObj = { + _fire: function(evt, args){ + if(this[evt]){ + this[evt].apply(this, args||[]); + } + return this; + } + }; + + var _chain = function(animations){ + this._index = -1; + this._animations = animations||[]; + this._current = this._onAnimateCtx = this._onEndCtx = null; + + this.duration = 0; + arrayUtil.forEach(this._animations, function(a){ + this.duration += a.duration; + if(a.delay){ this.duration += a.delay; } + }, this); + }; + _chain.prototype = new Evented(); + lang.extend(_chain, { + _onAnimate: function(){ + this._fire("onAnimate", arguments); + }, + _onEnd: function(){ + connect.disconnect(this._onAnimateCtx); + connect.disconnect(this._onEndCtx); + this._onAnimateCtx = this._onEndCtx = null; + if(this._index + 1 == this._animations.length){ + this._fire("onEnd"); + }else{ + // switch animations + this._current = this._animations[++this._index]; + this._onAnimateCtx = connect.connect(this._current, "onAnimate", this, "_onAnimate"); + this._onEndCtx = connect.connect(this._current, "onEnd", this, "_onEnd"); + this._current.play(0, true); + } + }, + play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ + if(!this._current){ this._current = this._animations[this._index = 0]; } + if(!gotoStart && this._current.status() == "playing"){ return this; } + var beforeBegin = connect.connect(this._current, "beforeBegin", this, function(){ + this._fire("beforeBegin"); + }), + onBegin = connect.connect(this._current, "onBegin", this, function(arg){ + this._fire("onBegin", arguments); + }), + onPlay = connect.connect(this._current, "onPlay", this, function(arg){ + this._fire("onPlay", arguments); + connect.disconnect(beforeBegin); + connect.disconnect(onBegin); + connect.disconnect(onPlay); + }); + if(this._onAnimateCtx){ + connect.disconnect(this._onAnimateCtx); + } + this._onAnimateCtx = connect.connect(this._current, "onAnimate", this, "_onAnimate"); + if(this._onEndCtx){ + connect.disconnect(this._onEndCtx); + } + this._onEndCtx = connect.connect(this._current, "onEnd", this, "_onEnd"); + this._current.play.apply(this._current, arguments); + return this; + }, + pause: function(){ + if(this._current){ + var e = connect.connect(this._current, "onPause", this, function(arg){ + this._fire("onPause", arguments); + connect.disconnect(e); + }); + this._current.pause(); + } + return this; + }, + gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ + this.pause(); + var offset = this.duration * percent; + this._current = null; + arrayUtil.some(this._animations, function(a){ + if(a.duration <= offset){ + this._current = a; + return true; + } + offset -= a.duration; + return false; + }); + if(this._current){ + this._current.gotoPercent(offset / this._current.duration, andPlay); + } + return this; + }, + stop: function(/*boolean?*/ gotoEnd){ + if(this._current){ + if(gotoEnd){ + for(; this._index + 1 < this._animations.length; ++this._index){ + this._animations[this._index].stop(true); + } + this._current = this._animations[this._index]; + } + var e = connect.connect(this._current, "onStop", this, function(arg){ + this._fire("onStop", arguments); + connect.disconnect(e); + }); + this._current.stop(); + } + return this; + }, + status: function(){ + return this._current ? this._current.status() : "stopped"; + }, + destroy: function(){ + if(this._onAnimateCtx){ connect.disconnect(this._onAnimateCtx); } + if(this._onEndCtx){ connect.disconnect(this._onEndCtx); } + } + }); + lang.extend(_chain, _baseObj); + + coreFx.chain = /*===== dojo.fx.chain = =====*/ function(/*dojo.Animation[]*/ animations){ + // summary: + // Chain a list of `dojo.Animation`s to run in sequence + // + // description: + // Return a `dojo.Animation` which will play all passed + // `dojo.Animation` instances in sequence, firing its own + // synthesized events simulating a single animation. (eg: + // onEnd of this animation means the end of the chain, + // not the individual animations within) + // + // example: + // Once `node` is faded out, fade in `otherNode` + // | dojo.fx.chain([ + // | dojo.fadeIn({ node:node }), + // | dojo.fadeOut({ node:otherNode }) + // | ]).play(); + // + return new _chain(animations); // dojo.Animation + }; + + var _combine = function(animations){ + this._animations = animations||[]; + this._connects = []; + this._finished = 0; + + this.duration = 0; + arrayUtil.forEach(animations, function(a){ + var duration = a.duration; + if(a.delay){ duration += a.delay; } + if(this.duration < duration){ this.duration = duration; } + this._connects.push(connect.connect(a, "onEnd", this, "_onEnd")); + }, this); + + this._pseudoAnimation = new baseFx.Animation({curve: [0, 1], duration: this.duration}); + var self = this; + arrayUtil.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"], + function(evt){ + self._connects.push(connect.connect(self._pseudoAnimation, evt, + function(){ self._fire(evt, arguments); } + )); + } + ); + }; + lang.extend(_combine, { + _doAction: function(action, args){ + arrayUtil.forEach(this._animations, function(a){ + a[action].apply(a, args); + }); + return this; + }, + _onEnd: function(){ + if(++this._finished > this._animations.length){ + this._fire("onEnd"); + } + }, + _call: function(action, args){ + var t = this._pseudoAnimation; + t[action].apply(t, args); + }, + play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ + this._finished = 0; + this._doAction("play", arguments); + this._call("play", arguments); + return this; + }, + pause: function(){ + this._doAction("pause", arguments); + this._call("pause", arguments); + return this; + }, + gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ + var ms = this.duration * percent; + arrayUtil.forEach(this._animations, function(a){ + a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay); + }); + this._call("gotoPercent", arguments); + return this; + }, + stop: function(/*boolean?*/ gotoEnd){ + this._doAction("stop", arguments); + this._call("stop", arguments); + return this; + }, + status: function(){ + return this._pseudoAnimation.status(); + }, + destroy: function(){ + arrayUtil.forEach(this._connects, connect.disconnect); + } + }); + lang.extend(_combine, _baseObj); + + coreFx.combine = /*===== dojo.fx.combine = =====*/ function(/*dojo.Animation[]*/ animations){ + // summary: + // Combine a list of `dojo.Animation`s to run in parallel + // + // description: + // Combine an array of `dojo.Animation`s to run in parallel, + // providing a new `dojo.Animation` instance encompasing each + // animation, firing standard animation events. + // + // example: + // Fade out `node` while fading in `otherNode` simultaneously + // | dojo.fx.combine([ + // | dojo.fadeIn({ node:node }), + // | dojo.fadeOut({ node:otherNode }) + // | ]).play(); + // + // example: + // When the longest animation ends, execute a function: + // | var anim = dojo.fx.combine([ + // | dojo.fadeIn({ node: n, duration:700 }), + // | dojo.fadeOut({ node: otherNode, duration: 300 }) + // | ]); + // | dojo.connect(anim, "onEnd", function(){ + // | // overall animation is done. + // | }); + // | anim.play(); // play the animation + // + return new _combine(animations); // dojo.Animation + }; + + coreFx.wipeIn = /*===== dojo.fx.wipeIn = =====*/ function(/*Object*/ args){ + // summary: + // Expand a node to it's natural height. + // + // description: + // Returns an animation that will expand the + // node defined in 'args' object from it's current height to + // it's natural height (with no scrollbar). + // Node must have no margin/border/padding. + // + // args: Object + // A hash-map of standard `dojo.Animation` constructor properties + // (such as easing: node: duration: and so on) + // + // example: + // | dojo.fx.wipeIn({ + // | node:"someId" + // | }).play() + var node = args.node = dom.byId(args.node), s = node.style, o; + + var anim = baseFx.animateProperty(lang.mixin({ + properties: { + height: { + // wrapped in functions so we wait till the last second to query (in case value has changed) + start: function(){ + // start at current [computed] height, but use 1px rather than 0 + // because 0 causes IE to display the whole panel + o = s.overflow; + s.overflow = "hidden"; + if(s.visibility == "hidden" || s.display == "none"){ + s.height = "1px"; + s.display = ""; + s.visibility = ""; + return 1; + }else{ + var height = domStyle.get(node, "height"); + return Math.max(height, 1); + } + }, + end: function(){ + return node.scrollHeight; + } + } + } + }, args)); + + var fini = function(){ + s.height = "auto"; + s.overflow = o; + }; + connect.connect(anim, "onStop", fini); + connect.connect(anim, "onEnd", fini); + + return anim; // dojo.Animation + }; + + coreFx.wipeOut = /*===== dojo.fx.wipeOut = =====*/ function(/*Object*/ args){ + // summary: + // Shrink a node to nothing and hide it. + // + // description: + // Returns an animation that will shrink node defined in "args" + // from it's current height to 1px, and then hide it. + // + // args: Object + // A hash-map of standard `dojo.Animation` constructor properties + // (such as easing: node: duration: and so on) + // + // example: + // | dojo.fx.wipeOut({ node:"someId" }).play() + + var node = args.node = dom.byId(args.node), s = node.style, o; + + var anim = baseFx.animateProperty(lang.mixin({ + properties: { + height: { + end: 1 // 0 causes IE to display the whole panel + } + } + }, args)); + + connect.connect(anim, "beforeBegin", function(){ + o = s.overflow; + s.overflow = "hidden"; + s.display = ""; + }); + var fini = function(){ + s.overflow = o; + s.height = "auto"; + s.display = "none"; + }; + connect.connect(anim, "onStop", fini); + connect.connect(anim, "onEnd", fini); + + return anim; // dojo.Animation + }; + + coreFx.slideTo = /*===== dojo.fx.slideTo = =====*/ function(/*Object*/ args){ + // summary: + // Slide a node to a new top/left position + // + // description: + // Returns an animation that will slide "node" + // defined in args Object from its current position to + // the position defined by (args.left, args.top). + // + // args: Object + // A hash-map of standard `dojo.Animation` constructor properties + // (such as easing: node: duration: and so on). Special args members + // are `top` and `left`, which indicate the new position to slide to. + // + // example: + // | .slideTo({ node: node, left:"40", top:"50", units:"px" }).play() + + var node = args.node = dom.byId(args.node), + top = null, left = null; + + var init = (function(n){ + return function(){ + var cs = domStyle.getComputedStyle(n); + var pos = cs.position; + top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0); + left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0); + if(pos != 'absolute' && pos != 'relative'){ + var ret = geom.position(n, true); + top = ret.y; + left = ret.x; + n.style.position="absolute"; + n.style.top=top+"px"; + n.style.left=left+"px"; + } + }; + })(node); + init(); + + var anim = baseFx.animateProperty(lang.mixin({ + properties: { + top: args.top || 0, + left: args.left || 0 + } + }, args)); + connect.connect(anim, "beforeBegin", anim, init); + + return anim; // dojo.Animation + }; + + return coreFx; +}); + +}, +'dojox/gfx/fx':function(){ +define("dojox/gfx/fx", ["dojo/_base/lang", "./_base", "./matrix", "dojo/_base/Color", "dojo/_base/array", "dojo/_base/fx", "dojo/_base/connect"], + function(lang, g, m, Color, arr, fx, Hub){ + var fxg = g.fx = {}; + /*===== g = dojox.gfx; fxg = dojox.gfx.fx; =====*/ + + // Generic interpolators. Should they be moved to dojox.fx? + + function InterpolNumber(start, end){ + this.start = start, this.end = end; + } + InterpolNumber.prototype.getValue = function(r){ + return (this.end - this.start) * r + this.start; + }; + + function InterpolUnit(start, end, units){ + this.start = start, this.end = end; + this.units = units; + } + InterpolUnit.prototype.getValue = function(r){ + return (this.end - this.start) * r + this.start + this.units; + }; + + function InterpolColor(start, end){ + this.start = start, this.end = end; + this.temp = new Color(); + } + InterpolColor.prototype.getValue = function(r){ + return Color.blendColors(this.start, this.end, r, this.temp); + }; + + function InterpolValues(values){ + this.values = values; + this.length = values.length; + } + InterpolValues.prototype.getValue = function(r){ + return this.values[Math.min(Math.floor(r * this.length), this.length - 1)]; + }; + + function InterpolObject(values, def){ + this.values = values; + this.def = def ? def : {}; + } + InterpolObject.prototype.getValue = function(r){ + var ret = lang.clone(this.def); + for(var i in this.values){ + ret[i] = this.values[i].getValue(r); + } + return ret; + }; + + function InterpolTransform(stack, original){ + this.stack = stack; + this.original = original; + } + InterpolTransform.prototype.getValue = function(r){ + var ret = []; + arr.forEach(this.stack, function(t){ + if(t instanceof m.Matrix2D){ + ret.push(t); + return; + } + if(t.name == "original" && this.original){ + ret.push(this.original); + return; + } + if(!(t.name in m)){ return; } + var f = m[t.name]; + if(typeof f != "function"){ + // constant + ret.push(f); + return; + } + var val = arr.map(t.start, function(v, i){ + return (t.end[i] - v) * r + v; + }), + matrix = f.apply(m, val); + if(matrix instanceof m.Matrix2D){ + ret.push(matrix); + } + }, this); + return ret; + }; + + var transparent = new Color(0, 0, 0, 0); + + function getColorInterpol(prop, obj, name, def){ + if(prop.values){ + return new InterpolValues(prop.values); + } + var value, start, end; + if(prop.start){ + start = g.normalizeColor(prop.start); + }else{ + start = value = obj ? (name ? obj[name] : obj) : def; + } + if(prop.end){ + end = g.normalizeColor(prop.end); + }else{ + if(!value){ + value = obj ? (name ? obj[name] : obj) : def; + } + end = value; + } + return new InterpolColor(start, end); + } + + function getNumberInterpol(prop, obj, name, def){ + if(prop.values){ + return new InterpolValues(prop.values); + } + var value, start, end; + if(prop.start){ + start = prop.start; + }else{ + start = value = obj ? obj[name] : def; + } + if(prop.end){ + end = prop.end; + }else{ + if(typeof value != "number"){ + value = obj ? obj[name] : def; + } + end = value; + } + return new InterpolNumber(start, end); + } + + fxg.animateStroke = function(/*Object*/ args){ + // summary: + // Returns an animation which will change stroke properties over time. + // example: + // | dojox.gfx.fx.animateStroke{{ + // | shape: shape, + // | duration: 500, + // | color: {start: "red", end: "green"}, + // | width: {end: 15}, + // | join: {values: ["miter", "bevel", "round"]} + // | }).play(); + if(!args.easing){ args.easing = fx._defaultEasing; } + var anim = new fx.Animation(args), shape = args.shape, stroke; + Hub.connect(anim, "beforeBegin", anim, function(){ + stroke = shape.getStroke(); + var prop = args.color, values = {}, value, start, end; + if(prop){ + values.color = getColorInterpol(prop, stroke, "color", transparent); + } + prop = args.style; + if(prop && prop.values){ + values.style = new InterpolValues(prop.values); + } + prop = args.width; + if(prop){ + values.width = getNumberInterpol(prop, stroke, "width", 1); + } + prop = args.cap; + if(prop && prop.values){ + values.cap = new InterpolValues(prop.values); + } + prop = args.join; + if(prop){ + if(prop.values){ + values.join = new InterpolValues(prop.values); + }else{ + start = prop.start ? prop.start : (stroke && stroke.join || 0); + end = prop.end ? prop.end : (stroke && stroke.join || 0); + if(typeof start == "number" && typeof end == "number"){ + values.join = new InterpolNumber(start, end); + } + } + } + this.curve = new InterpolObject(values, stroke); + }); + Hub.connect(anim, "onAnimate", shape, "setStroke"); + return anim; // dojo.Animation + }; + + fxg.animateFill = function(/*Object*/ args){ + // summary: + // Returns an animation which will change fill color over time. + // Only solid fill color is supported at the moment + // example: + // | dojox.gfx.fx.animateFill{{ + // | shape: shape, + // | duration: 500, + // | color: {start: "red", end: "green"} + // | }).play(); + if(!args.easing){ args.easing = fx._defaultEasing; } + var anim = new fx.Animation(args), shape = args.shape, fill; + Hub.connect(anim, "beforeBegin", anim, function(){ + fill = shape.getFill(); + var prop = args.color, values = {}; + if(prop){ + this.curve = getColorInterpol(prop, fill, "", transparent); + } + }); + Hub.connect(anim, "onAnimate", shape, "setFill"); + return anim; // dojo.Animation + }; + + fxg.animateFont = function(/*Object*/ args){ + // summary: + // Returns an animation which will change font properties over time. + // example: + // | dojox.gfx.fx.animateFont{{ + // | shape: shape, + // | duration: 500, + // | variant: {values: ["normal", "small-caps"]}, + // | size: {end: 10, units: "pt"} + // | }).play(); + if(!args.easing){ args.easing = fx._defaultEasing; } + var anim = new fx.Animation(args), shape = args.shape, font; + Hub.connect(anim, "beforeBegin", anim, function(){ + font = shape.getFont(); + var prop = args.style, values = {}, value, start, end; + if(prop && prop.values){ + values.style = new InterpolValues(prop.values); + } + prop = args.variant; + if(prop && prop.values){ + values.variant = new InterpolValues(prop.values); + } + prop = args.weight; + if(prop && prop.values){ + values.weight = new InterpolValues(prop.values); + } + prop = args.family; + if(prop && prop.values){ + values.family = new InterpolValues(prop.values); + } + prop = args.size; + if(prop && prop.units){ + start = parseFloat(prop.start ? prop.start : (shape.font && shape.font.size || "0")); + end = parseFloat(prop.end ? prop.end : (shape.font && shape.font.size || "0")); + values.size = new InterpolUnit(start, end, prop.units); + } + this.curve = new InterpolObject(values, font); + }); + Hub.connect(anim, "onAnimate", shape, "setFont"); + return anim; // dojo.Animation + }; + + fxg.animateTransform = function(/*Object*/ args){ + // summary: + // Returns an animation which will change transformation over time. + // example: + // | dojox.gfx.fx.animateTransform{{ + // | shape: shape, + // | duration: 500, + // | transform: [ + // | {name: "translate", start: [0, 0], end: [200, 200]}, + // | {name: "original"} + // | ] + // | }).play(); + if(!args.easing){ args.easing = fx._defaultEasing; } + var anim = new fx.Animation(args), shape = args.shape, original; + Hub.connect(anim, "beforeBegin", anim, function(){ + original = shape.getTransform(); + this.curve = new InterpolTransform(args.transform, original); + }); + Hub.connect(anim, "onAnimate", shape, "setTransform"); + return anim; // dojo.Animation + }; + + return fxg; +}); + +}, +'dojox/charting/action2d/PlotAction':function(){ +define("dojox/charting/action2d/PlotAction", ["dojo/_base/connect", "dojo/_base/declare", "./Base", "dojo/fx/easing", "dojox/lang/functional", + "dojox/lang/functional/object"], + function(hub, declare, Base, dfe, df, dlfo){ + + /*===== + dojox.charting.action2d.__PlotActionCtorArgs = function(duration, easing){ + // summary: + // The base keyword arguments object for creating an action2d. + // duration: Number? + // The amount of time in milliseconds for an animation to last. Default is 400. + // easing: dojo.fx.easing.*? + // An easing object (see dojo.fx.easing) for use in an animation. The + // default is dojo.fx.easing.backOut. + this.duration = duration; + this.easing = easing; + } + var Base = dojox.charting.action2d.Base; + =====*/ + + var DEFAULT_DURATION = 400, // ms + DEFAULT_EASING = dfe.backOut; + + return declare("dojox.charting.action2d.PlotAction", Base, { + // summary: + // Base action class for plot actions. + + overOutEvents: {onmouseover: 1, onmouseout: 1}, + + constructor: function(chart, plot, kwargs){ + // summary: + // Create a new base PlotAction. + // chart: dojox.charting.Chart + // The chart this action applies to. + // plot: String? + // The name of the plot this action belongs to. If none is passed "default" is assumed. + // kwargs: dojox.charting.action2d.__PlotActionCtorArgs? + // Optional arguments for the action. + this.anim = {}; + + // process common optional named parameters + if(!kwargs){ kwargs = {}; } + this.duration = kwargs.duration ? kwargs.duration : DEFAULT_DURATION; + this.easing = kwargs.easing ? kwargs.easing : DEFAULT_EASING; + }, + + connect: function(){ + // summary: + // Connect this action to the given plot. + this.handle = this.chart.connectToPlot(this.plot.name, this, "process"); + }, + + disconnect: function(){ + // summary: + // Disconnect this action from the given plot, if connected. + if(this.handle){ + hub.disconnect(this.handle); + this.handle = null; + } + }, + + reset: function(){ + // summary: + // Reset the action. + }, + + destroy: function(){ + // summary: + // Do any cleanup needed when destroying parent elements. + this.inherited(arguments); + df.forIn(this.anim, function(o){ + df.forIn(o, function(anim){ + anim.action.stop(true); + }); + }); + this.anim = {}; + } + }); +}); + +}, +'dijit/BackgroundIframe':function(){ +define("dijit/BackgroundIframe", [ + "require", // require.toUrl + ".", // to export dijit.BackgroundIframe + "dojo/_base/config", + "dojo/dom-construct", // domConstruct.create + "dojo/dom-style", // domStyle.set + "dojo/_base/lang", // lang.extend lang.hitch + "dojo/on", + "dojo/_base/sniff", // has("ie"), has("mozilla"), has("quirks") + "dojo/_base/window" // win.doc.createElement +], function(require, dijit, config, domConstruct, domStyle, lang, on, has, win){ + + // module: + // dijit/BackgroundIFrame + // summary: + // new dijit.BackgroundIframe(node) + // Makes a background iframe as a child of node, that fills + // area (and position) of node + + // TODO: remove _frames, it isn't being used much, since popups never release their + // iframes (see [22236]) + var _frames = new function(){ + // summary: + // cache of iframes + + var queue = []; + + this.pop = function(){ + var iframe; + if(queue.length){ + iframe = queue.pop(); + iframe.style.display=""; + }else{ + if(has("ie") < 9){ + var burl = config["dojoBlankHtmlUrl"] || require.toUrl("dojo/resources/blank.html") || "javascript:\"\""; + var html="<iframe src='" + burl + "' role='presentation'" + + " style='position: absolute; left: 0px; top: 0px;" + + "z-index: -1; filter:Alpha(Opacity=\"0\");'>"; + iframe = win.doc.createElement(html); + }else{ + iframe = domConstruct.create("iframe"); + iframe.src = 'javascript:""'; + iframe.className = "dijitBackgroundIframe"; + iframe.setAttribute("role", "presentation"); + domStyle.set(iframe, "opacity", 0.1); + } + iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work. + } + return iframe; + }; + + this.push = function(iframe){ + iframe.style.display="none"; + queue.push(iframe); + } + }(); + + + dijit.BackgroundIframe = function(/*DomNode*/ node){ + // summary: + // For IE/FF z-index schenanigans. id attribute is required. + // + // description: + // new dijit.BackgroundIframe(node) + // Makes a background iframe as a child of node, that fills + // area (and position) of node + + if(!node.id){ throw new Error("no id"); } + if(has("ie") || has("mozilla")){ + var iframe = (this.iframe = _frames.pop()); + node.appendChild(iframe); + if(has("ie")<7 || has("quirks")){ + this.resize(node); + this._conn = on(node, 'resize', lang.hitch(this, function(){ + this.resize(node); + })); + }else{ + domStyle.set(iframe, { + width: '100%', + height: '100%' + }); + } + } + }; + + lang.extend(dijit.BackgroundIframe, { + resize: function(node){ + // summary: + // Resize the iframe so it's the same size as node. + // Needed on IE6 and IE/quirks because height:100% doesn't work right. + if(this.iframe){ + domStyle.set(this.iframe, { + width: node.offsetWidth + 'px', + height: node.offsetHeight + 'px' + }); + } + }, + destroy: function(){ + // summary: + // destroy the iframe + if(this._conn){ + this._conn.remove(); + this._conn = null; + } + if(this.iframe){ + _frames.push(this.iframe); + delete this.iframe; + } + } + }); + + return dijit.BackgroundIframe; +}); + +}, +'dojox/main':function(){ +define("dojox/main", ["dojo/_base/kernel"], function(dojo) { + // module: + // dojox/main + // summary: + // The dojox package main module; dojox package is somewhat unusual in that the main module currently just provides an empty object. + + return dojo.dojox; +}); +}, +'dojox/charting/action2d/Magnify':function(){ +define("dojox/charting/action2d/Magnify", ["dojo/_base/connect", "dojo/_base/declare", + "./PlotAction", "dojox/gfx/matrix", + "dojox/gfx/fx", "dojo/fx", "dojo/fx/easing"], + function(Hub, declare, PlotAction, m, gf, df, dfe){ + + /*===== + dojo.declare("dojox.charting.action2d.__MagnifyCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // scale: Number? + // The amount to magnify the given object to. Default is 2. + scale: 2 + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SCALE = 2; + + return declare("dojox.charting.action2d.Magnify", PlotAction, { + // summary: + // Create an action that magnifies the object the action is applied to. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut, // easing for the action + scale: DEFAULT_SCALE // scale of magnification + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the magnifying action. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot to apply the action to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__MagnifyCtorArgs? + // Optional keyword arguments for this action. + + // process optional named parameters + this.scale = kwArgs && typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the magnifying action. + if(!o.shape || !(o.type in this.overOutEvents) || + !("cx" in o) || !("cy" in o)){ return; } + + var runName = o.run.name, index = o.index, vector = [], anim, init, scale; + + if(runName in this.anim){ + anim = this.anim[runName][index]; + }else{ + this.anim[runName] = {}; + } + + if(anim){ + anim.action.stop(true); + }else{ + this.anim[runName][index] = anim = {}; + } + + if(o.type == "onmouseover"){ + init = m.identity; + scale = this.scale; + }else{ + init = m.scaleAt(this.scale, o.cx, o.cy); + scale = 1 / this.scale; + } + + var kwArgs = { + shape: o.shape, + duration: this.duration, + easing: this.easing, + transform: [ + {name: "scaleAt", start: [1, o.cx, o.cy], end: [scale, o.cx, o.cy]}, + init + ] + }; + if(o.shape){ + vector.push(gf.animateTransform(kwArgs)); + } + if(o.oultine){ + kwArgs.shape = o.outline; + vector.push(gf.animateTransform(kwArgs)); + } + if(o.shadow){ + kwArgs.shape = o.shadow; + vector.push(gf.animateTransform(kwArgs)); + } + + if(!vector.length){ + delete this.anim[runName][index]; + return; + } + + anim.action = df.combine(vector); + if(o.type == "onmouseout"){ + Hub.connect(anim.action, "onEnd", this, function(){ + if(this.anim[runName]){ + delete this.anim[runName][index]; + } + }); + } + anim.action.play(); + } + }); + +}); + +}, +'dojo/Stateful':function(){ +define(["./_base/kernel", "./_base/declare", "./_base/lang", "./_base/array"], function(dojo, declare, lang, array) { + // module: + // dojo/Stateful + // summary: + // TODOC + +return dojo.declare("dojo.Stateful", null, { + // summary: + // Base class for objects that provide named properties with optional getter/setter + // control and the ability to watch for property changes + // example: + // | var obj = new dojo.Stateful(); + // | obj.watch("foo", function(){ + // | console.log("foo changed to " + this.get("foo")); + // | }); + // | obj.set("foo","bar"); + postscript: function(mixin){ + if(mixin){ + lang.mixin(this, mixin); + } + }, + + get: function(/*String*/name){ + // summary: + // Get a property on a Stateful instance. + // name: + // The property to get. + // returns: + // The property value on this Stateful instance. + // description: + // Get a named property on a Stateful object. The property may + // potentially be retrieved via a getter method in subclasses. In the base class + // this just retrieves the object's property. + // For example: + // | stateful = new dojo.Stateful({foo: 3}); + // | stateful.get("foo") // returns 3 + // | stateful.foo // returns 3 + + return this[name]; //Any + }, + set: function(/*String*/name, /*Object*/value){ + // summary: + // Set a property on a Stateful instance + // name: + // The property to set. + // value: + // The value to set in the property. + // returns: + // The function returns this dojo.Stateful instance. + // description: + // Sets named properties on a stateful object and notifies any watchers of + // the property. A programmatic setter may be defined in subclasses. + // For example: + // | stateful = new dojo.Stateful(); + // | stateful.watch(function(name, oldValue, value){ + // | // this will be called on the set below + // | } + // | stateful.set(foo, 5); + // + // set() may also be called with a hash of name/value pairs, ex: + // | myObj.set({ + // | foo: "Howdy", + // | bar: 3 + // | }) + // This is equivalent to calling set(foo, "Howdy") and set(bar, 3) + if(typeof name === "object"){ + for(var x in name){ + this.set(x, name[x]); + } + return this; + } + var oldValue = this[name]; + this[name] = value; + if(this._watchCallbacks){ + this._watchCallbacks(name, oldValue, value); + } + return this; //dojo.Stateful + }, + watch: function(/*String?*/name, /*Function*/callback){ + // summary: + // Watches a property for changes + // name: + // Indicates the property to watch. This is optional (the callback may be the + // only parameter), and if omitted, all the properties will be watched + // returns: + // An object handle for the watch. The unwatch method of this object + // can be used to discontinue watching this property: + // | var watchHandle = obj.watch("foo", callback); + // | watchHandle.unwatch(); // callback won't be called now + // callback: + // The function to execute when the property changes. This will be called after + // the property has been changed. The callback will be called with the |this| + // set to the instance, the first argument as the name of the property, the + // second argument as the old value and the third argument as the new value. + + var callbacks = this._watchCallbacks; + if(!callbacks){ + var self = this; + callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){ + var notify = function(propertyCallbacks){ + if(propertyCallbacks){ + propertyCallbacks = propertyCallbacks.slice(); + for(var i = 0, l = propertyCallbacks.length; i < l; i++){ + try{ + propertyCallbacks[i].call(self, name, oldValue, value); + }catch(e){ + console.error(e); + } + } + } + }; + notify(callbacks['_' + name]); + if(!ignoreCatchall){ + notify(callbacks["*"]); // the catch-all + } + }; // we use a function instead of an object so it will be ignored by JSON conversion + } + if(!callback && typeof name === "function"){ + callback = name; + name = "*"; + }else{ + // prepend with dash to prevent name conflicts with function (like "name" property) + name = '_' + name; + } + var propertyCallbacks = callbacks[name]; + if(typeof propertyCallbacks !== "object"){ + propertyCallbacks = callbacks[name] = []; + } + propertyCallbacks.push(callback); + return { + unwatch: function(){ + propertyCallbacks.splice(array.indexOf(propertyCallbacks, callback), 1); + } + }; //Object + } + +}); + +}); + +}, +'dojox/charting/plot2d/Markers':function(){ +define("dojox/charting/plot2d/Markers", ["dojo/_base/declare", "./Default"], function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default +=====*/ + return declare("dojox.charting.plot2d.Markers", Default, { + // summary: + // A convenience plot to draw a line chart with markers. + constructor: function(){ + // summary: + // Set up the plot for lines and markers. + this.opt.markers = true; + } + }); +}); + +}, +'dojox/charting/plot2d/Bubble':function(){ +define("dojox/charting/plot2d/Bubble", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", + "./Base", "./common", "dojox/lang/functional", "dojox/lang/functional/reversed", + "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, arr, Base, dc, df, dfr, du, fx){ +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Bubble", Base, { + // summary: + // A plot representing bubbles. Note that data for Bubbles requires 3 parameters, + // in the form of: { x, y, size }, where size determines the size of the bubble. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + animate: null // animate bars into place + }, + optionalParams: { + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create a plot of bubbles. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs? + // Optional keyword arguments object to help define plot parameters. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + // override the render so that we are plotting only circles. + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Bubble + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + + var t = this.chart.theme, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + events = this.events(); + + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(!run.data.length){ + run.dirty = false; + t.skip(); + continue; + } + + if(typeof run.data[0] == "number"){ + console.warn("dojox.charting.plot2d.Bubble: the data in the following series cannot be rendered as a bubble chart; ", run); + continue; + } + + var theme = t.next("circle", [this.opt, run]), s = run.group, + points = arr.map(run.data, function(v, i){ + return v ? { + x: ht(v.x) + offsets.l, + y: dim.height - offsets.b - vt(v.y), + radius: this._vScaler.bounds.scale * (v.size / 2) + } : null; + }, this); + + var frontCircles = null, outlineCircles = null, shadowCircles = null; + + // make shadows if needed + if(theme.series.shadow){ + shadowCircles = arr.map(points, function(item){ + if(item !== null){ + var finalTheme = t.addMixin(theme, "circle", item, true), + shadow = finalTheme.series.shadow; + var shape = s.createCircle({ + cx: item.x + shadow.dx, cy: item.y + shadow.dy, r: item.radius + }).setStroke(shadow).setFill(shadow.color); + if(this.animate){ + this._animateBubble(shape, dim.height - offsets.b, item.radius); + } + return shape; + } + return null; + }, this); + if(shadowCircles.length){ + run.dyn.shadow = shadowCircles[shadowCircles.length - 1].getStroke(); + } + } + + // make outlines if needed + if(theme.series.outline){ + outlineCircles = arr.map(points, function(item){ + if(item !== null){ + var finalTheme = t.addMixin(theme, "circle", item, true), + outline = dc.makeStroke(finalTheme.series.outline); + outline.width = 2 * outline.width + theme.series.stroke.width; + var shape = s.createCircle({ + cx: item.x, cy: item.y, r: item.radius + }).setStroke(outline); + if(this.animate){ + this._animateBubble(shape, dim.height - offsets.b, item.radius); + } + return shape; + } + return null; + }, this); + if(outlineCircles.length){ + run.dyn.outline = outlineCircles[outlineCircles.length - 1].getStroke(); + } + } + + // run through the data and add the circles. + frontCircles = arr.map(points, function(item){ + if(item !== null){ + var finalTheme = t.addMixin(theme, "circle", item, true), + rect = { + x: item.x - item.radius, + y: item.y - item.radius, + width: 2 * item.radius, + height: 2 * item.radius + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createCircle({ + cx: item.x, cy: item.y, r: item.radius + }).setFill(specialFill).setStroke(finalTheme.series.stroke); + if(this.animate){ + this._animateBubble(shape, dim.height - offsets.b, item.radius); + } + return shape; + } + return null; + }, this); + if(frontCircles.length){ + run.dyn.fill = frontCircles[frontCircles.length - 1].getFill(); + run.dyn.stroke = frontCircles[frontCircles.length - 1].getStroke(); + } + + if(events){ + var eventSeries = new Array(frontCircles.length); + arr.forEach(frontCircles, function(s, i){ + if(s !== null){ + var o = { + element: "circle", + index: i, + run: run, + shape: s, + outline: outlineCircles && outlineCircles[i] || null, + shadow: shadowCircles && shadowCircles[i] || null, + x: run.data[i].x, + y: run.data[i].y, + r: run.data[i].size / 2, + cx: points[i].x, + cy: points[i].y, + cr: points[i].radius + }; + this._connectEvents(o); + eventSeries[i] = o; + } + }, this); + this._eventSeries[run.name] = eventSeries; + }else{ + delete this._eventSeries[run.name]; + } + + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Bubble + }, + _animateBubble: function(shape, offset, size){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, offset], end: [0, 0]}, + {name: "scale", start: [0, 1/size], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); + +}, +'dojo/touch':function(){ +define(["./_base/kernel", "./on", "./has", "./mouse"], function(dojo, on, has, mouse){ +// module: +// dojo/touch + +/*===== + dojo.touch = { + // summary: + // This module provides unified touch event handlers by exporting + // press, move, release and cancel which can also run well on desktop. + // Based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html + // + // example: + // 1. Used with dojo.connect() + // | dojo.connect(node, dojo.touch.press, function(e){}); + // | dojo.connect(node, dojo.touch.move, function(e){}); + // | dojo.connect(node, dojo.touch.release, function(e){}); + // | dojo.connect(node, dojo.touch.cancel, function(e){}); + // + // 2. Used with dojo.on + // | define(["dojo/on", "dojo/touch"], function(on, touch){ + // | on(node, touch.press, function(e){}); + // | on(node, touch.move, function(e){}); + // | on(node, touch.release, function(e){}); + // | on(node, touch.cancel, function(e){}); + // + // 3. Used with dojo.touch.* directly + // | dojo.touch.press(node, function(e){}); + // | dojo.touch.move(node, function(e){}); + // | dojo.touch.release(node, function(e){}); + // | dojo.touch.cancel(node, function(e){}); + + press: function(node, listener){ + // summary: + // Register a listener to 'touchstart'|'mousedown' for the given node + // node: Dom + // Target node to listen to + // listener: Function + // Callback function + // returns: + // A handle which will be used to remove the listener by handle.remove() + }, + move: function(node, listener){ + // summary: + // Register a listener to 'touchmove'|'mousemove' for the given node + // node: Dom + // Target node to listen to + // listener: Function + // Callback function + // returns: + // A handle which will be used to remove the listener by handle.remove() + }, + release: function(node, listener){ + // summary: + // Register a listener to 'touchend'|'mouseup' for the given node + // node: Dom + // Target node to listen to + // listener: Function + // Callback function + // returns: + // A handle which will be used to remove the listener by handle.remove() + }, + cancel: function(node, listener){ + // summary: + // Register a listener to 'touchcancel'|'mouseleave' for the given node + // node: Dom + // Target node to listen to + // listener: Function + // Callback function + // returns: + // A handle which will be used to remove the listener by handle.remove() + } + }; +=====*/ + + function _handle(/*String - press | move | release | cancel*/type){ + return function(node, listener){//called by on(), see dojo.on + return on(node, type, listener); + }; + } + var touch = has("touch"); + //device neutral events - dojo.touch.press|move|release|cancel + dojo.touch = { + press: _handle(touch ? "touchstart": "mousedown"), + move: _handle(touch ? "touchmove": "mousemove"), + release: _handle(touch ? "touchend": "mouseup"), + cancel: touch ? _handle("touchcancel") : mouse.leave + }; + return dojo.touch; +}); +}, +'dojox/gfx/gradutils':function(){ +// Various generic utilities to deal with a linear gradient + +define(["./_base", "dojo/_base/lang", "./matrix", "dojo/_base/Color"], + function(g, lang, m, Color){ + + /*===== g= dojox.gfx =====*/ + var gradutils = g.gradutils = {}; + /*===== g= dojox.gfx; gradutils = dojox.gfx.gradutils; =====*/ + + function findColor(o, c){ + if(o <= 0){ + return c[0].color; + } + var len = c.length; + if(o >= 1){ + return c[len - 1].color; + } + //TODO: use binary search + for(var i = 0; i < len; ++i){ + var stop = c[i]; + if(stop.offset >= o){ + if(i){ + var prev = c[i - 1]; + return Color.blendColors(new Color(prev.color), new Color(stop.color), + (o - prev.offset) / (stop.offset - prev.offset)); + } + return stop.color; + } + } + return c[len - 1].color; + } + + gradutils.getColor = function(fill, pt){ + // summary: + // sample a color from a gradient using a point + // fill: Object: + // fill object + // pt: dojox.gfx.Point: + // point where to sample a color + var o; + if(fill){ + switch(fill.type){ + case "linear": + var angle = Math.atan2(fill.y2 - fill.y1, fill.x2 - fill.x1), + rotation = m.rotate(-angle), + projection = m.project(fill.x2 - fill.x1, fill.y2 - fill.y1), + p = m.multiplyPoint(projection, pt), + pf1 = m.multiplyPoint(projection, fill.x1, fill.y1), + pf2 = m.multiplyPoint(projection, fill.x2, fill.y2), + scale = m.multiplyPoint(rotation, pf2.x - pf1.x, pf2.y - pf1.y).x; + o = m.multiplyPoint(rotation, p.x - pf1.x, p.y - pf1.y).x / scale; + break; + case "radial": + var dx = pt.x - fill.cx, dy = pt.y - fill.cy; + o = Math.sqrt(dx * dx + dy * dy) / fill.r; + break; + } + return findColor(o, fill.colors); // dojo.Color + } + // simple color + return new Color(fill || [0, 0, 0, 0]); // dojo.Color + }; + + gradutils.reverse = function(fill){ + // summary: + // reverses a gradient + // fill: Object: + // fill object + if(fill){ + switch(fill.type){ + case "linear": + case "radial": + fill = lang.delegate(fill); + if(fill.colors){ + var c = fill.colors, l = c.length, i = 0, stop, + n = fill.colors = new Array(c.length); + for(; i < l; ++i){ + stop = c[i]; + n[i] = { + offset: 1 - stop.offset, + color: stop.color + }; + } + n.sort(function(a, b){ return a.offset - b.offset; }); + } + break; + } + } + return fill; // Object + }; + + return gradutils; +}); + +}, +'dojo/string':function(){ +define(["./_base/kernel", "./_base/lang"], function(dojo, lang) { + // module: + // dojo/string + // summary: + // TODOC + +lang.getObject("string", true, dojo); + +/*===== +dojo.string = { + // summary: String utilities for Dojo +}; +=====*/ + +dojo.string.rep = function(/*String*/str, /*Integer*/num){ + // summary: + // Efficiently replicate a string `n` times. + // str: + // the string to replicate + // num: + // number of times to replicate the string + + if(num <= 0 || !str){ return ""; } + + var buf = []; + for(;;){ + if(num & 1){ + buf.push(str); + } + if(!(num >>= 1)){ break; } + str += str; + } + return buf.join(""); // String +}; + +dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){ + // summary: + // Pad a string to guarantee that it is at least `size` length by + // filling with the character `ch` at either the start or end of the + // string. Pads at the start, by default. + // text: + // the string to pad + // size: + // length to provide padding + // ch: + // character to pad, defaults to '0' + // end: + // adds padding at the end if true, otherwise pads at start + // example: + // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++". + // | dojo.string.pad("Dojo", 10, "+", true); + + if(!ch){ + ch = '0'; + } + var out = String(text), + pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length)); + return end ? out + pad : pad + out; // String +}; + +dojo.string.substitute = function( /*String*/ template, + /*Object|Array*/map, + /*Function?*/ transform, + /*Object?*/ thisObject){ + // summary: + // Performs parameterized substitutions on a string. Throws an + // exception if any parameter is unmatched. + // template: + // a string with expressions in the form `${key}` to be replaced or + // `${key:format}` which specifies a format function. keys are case-sensitive. + // map: + // hash to search for substitutions + // transform: + // a function to process all parameters before substitution takes + // place, e.g. mylib.encodeXML + // thisObject: + // where to look for optional format function; default to the global + // namespace + // example: + // Substitutes two expressions in a string from an Array or Object + // | // returns "File 'foo.html' is not found in directory '/temp'." + // | // by providing substitution data in an Array + // | dojo.string.substitute( + // | "File '${0}' is not found in directory '${1}'.", + // | ["foo.html","/temp"] + // | ); + // | + // | // also returns "File 'foo.html' is not found in directory '/temp'." + // | // but provides substitution data in an Object structure. Dotted + // | // notation may be used to traverse the structure. + // | dojo.string.substitute( + // | "File '${name}' is not found in directory '${info.dir}'.", + // | { name: "foo.html", info: { dir: "/temp" } } + // | ); + // example: + // Use a transform function to modify the values: + // | // returns "file 'foo.html' is not found in directory '/temp'." + // | dojo.string.substitute( + // | "${0} is not found in ${1}.", + // | ["foo.html","/temp"], + // | function(str){ + // | // try to figure out the type + // | var prefix = (str.charAt(0) == "/") ? "directory": "file"; + // | return prefix + " '" + str + "'"; + // | } + // | ); + // example: + // Use a formatter + // | // returns "thinger -- howdy" + // | dojo.string.substitute( + // | "${0:postfix}", ["thinger"], null, { + // | postfix: function(value, key){ + // | return value + " -- howdy"; + // | } + // | } + // | ); + + thisObject = thisObject || dojo.global; + transform = transform ? + lang.hitch(thisObject, transform) : function(v){ return v; }; + + return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, + function(match, key, format){ + var value = lang.getObject(key, false, map); + if(format){ + value = lang.getObject(format, false, thisObject).call(thisObject, value, key); + } + return transform(value, key).toString(); + }); // String +}; + +/*===== +dojo.string.trim = function(str){ + // summary: + // Trims whitespace from both sides of the string + // str: String + // String to be trimmed + // returns: String + // Returns the trimmed string + // description: + // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript). + // The short yet performant version of this function is dojo.trim(), + // which is part of Dojo base. Uses String.prototype.trim instead, if available. + return ""; // String +} +=====*/ + +dojo.string.trim = String.prototype.trim ? + lang.trim : // aliasing to the native function + function(str){ + str = str.replace(/^\s+/, ''); + for(var i = str.length - 1; i >= 0; i--){ + if(/\S/.test(str.charAt(i))){ + str = str.substring(0, i + 1); + break; + } + } + return str; + }; + +return dojo.string; +}); + +}, +'dijit/registry':function(){ +define("dijit/registry", [ + "dojo/_base/array", // array.forEach array.map + "dojo/_base/sniff", // has("ie") + "dojo/_base/unload", // unload.addOnWindowUnload + "dojo/_base/window", // win.body + "." // dijit._scopeName +], function(array, has, unload, win, dijit){ + + // module: + // dijit/registry + // summary: + // Registry of existing widget on page, plus some utility methods. + // Must be accessed through AMD api, ex: + // require(["dijit/registry"], function(registry){ registry.byId("foo"); }) + + var _widgetTypeCtr = {}, hash = {}; + + var registry = { + // summary: + // A set of widgets indexed by id + + length: 0, + + add: function(/*dijit._Widget*/ widget){ + // summary: + // Add a widget to the registry. If a duplicate ID is detected, a error is thrown. + // + // widget: dijit._Widget + // Any dijit._Widget subclass. + if(hash[widget.id]){ + throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered"); + } + hash[widget.id] = widget; + this.length++; + }, + + remove: function(/*String*/ id){ + // summary: + // Remove a widget from the registry. Does not destroy the widget; simply + // removes the reference. + if(hash[id]){ + delete hash[id]; + this.length--; + } + }, + + byId: function(/*String|Widget*/ id){ + // summary: + // Find a widget by it's id. + // If passed a widget then just returns the widget. + return typeof id == "string" ? hash[id] : id; // dijit._Widget + }, + + byNode: function(/*DOMNode*/ node){ + // summary: + // Returns the widget corresponding to the given DOMNode + return hash[node.getAttribute("widgetId")]; // dijit._Widget + }, + + toArray: function(){ + // summary: + // Convert registry into a true Array + // + // example: + // Work with the widget .domNodes in a real Array + // | array.map(dijit.registry.toArray(), function(w){ return w.domNode; }); + + var ar = []; + for(var id in hash){ + ar.push(hash[id]); + } + return ar; // dijit._Widget[] + }, + + getUniqueId: function(/*String*/widgetType){ + // summary: + // Generates a unique id for a given widgetType + + var id; + do{ + id = widgetType + "_" + + (widgetType in _widgetTypeCtr ? + ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0); + }while(hash[id]); + return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String + }, + + findWidgets: function(/*DomNode*/ root){ + // summary: + // Search subtree under root returning widgets found. + // Doesn't search for nested widgets (ie, widgets inside other widgets). + + var outAry = []; + + function getChildrenHelper(root){ + for(var node = root.firstChild; node; node = node.nextSibling){ + if(node.nodeType == 1){ + var widgetId = node.getAttribute("widgetId"); + if(widgetId){ + var widget = hash[widgetId]; + if(widget){ // may be null on page w/multiple dojo's loaded + outAry.push(widget); + } + }else{ + getChildrenHelper(node); + } + } + } + } + + getChildrenHelper(root); + return outAry; + }, + + _destroyAll: function(){ + // summary: + // Code to destroy all widgets and do other cleanup on page unload + + // Clean up focus manager lingering references to widgets and nodes + dijit._curFocus = null; + dijit._prevFocus = null; + dijit._activeStack = []; + + // Destroy all the widgets, top down + array.forEach(registry.findWidgets(win.body()), function(widget){ + // Avoid double destroy of widgets like Menu that are attached to <body> + // even though they are logically children of other widgets. + if(!widget._destroyed){ + if(widget.destroyRecursive){ + widget.destroyRecursive(); + }else if(widget.destroy){ + widget.destroy(); + } + } + }); + }, + + getEnclosingWidget: function(/*DOMNode*/ node){ + // summary: + // Returns the widget whose DOM tree contains the specified DOMNode, or null if + // the node is not contained within the DOM tree of any widget + while(node){ + var id = node.getAttribute && node.getAttribute("widgetId"); + if(id){ + return hash[id]; + } + node = node.parentNode; + } + return null; + }, + + // In case someone needs to access hash. + // Actually, this is accessed from WidgetSet back-compatibility code + _hash: hash + }; + + if(has("ie")){ + // Only run _destroyAll() for IE because we think it's only necessary in that case, + // and because it causes problems on FF. See bug #3531 for details. + unload.addOnWindowUnload(function(){ + registry._destroyAll(); + }); + } + + /*===== + dijit.registry = { + // summary: + // A list of widgets on a page. + }; + =====*/ + dijit.registry = registry; + + return registry; +}); + +}, +'dojox/charting/plot2d/Lines':function(){ +define("dojox/charting/plot2d/Lines", ["dojo/_base/declare", "./Default"], function(declare, Default){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + return declare("dojox.charting.plot2d.Lines", Default, { + // summary: + // A convenience constructor to create a typical line chart. + constructor: function(){ + // summary: + // Preset our default plot to be line-based. + this.opt.lines = true; + } + }); +}); + +}, +'dijit/_base/manager':function(){ +define("dijit/_base/manager", [ + "dojo/_base/array", + "dojo/_base/config", // defaultDuration + "../registry", + ".." // for setting exports to dijit namespace +], function(array, config, registry, dijit){ + + // module: + // dijit/_base/manager + // summary: + // Shim to methods on registry, plus a few other declarations. + // New code should access dijit/registry directly when possible. + + /*===== + dijit.byId = function(id){ + // summary: + // Returns a widget by it's id, or if passed a widget, no-op (like dom.byId()) + // id: String|dijit._Widget + return registry.byId(id); // dijit._Widget + }; + + dijit.getUniqueId = function(widgetType){ + // summary: + // Generates a unique id for a given widgetType + // widgetType: String + return registry.getUniqueId(widgetType); // String + }; + + dijit.findWidgets = function(root){ + // summary: + // Search subtree under root returning widgets found. + // Doesn't search for nested widgets (ie, widgets inside other widgets). + // root: DOMNode + return registry.findWidgets(root); + }; + + dijit._destroyAll = function(){ + // summary: + // Code to destroy all widgets and do other cleanup on page unload + + return registry._destroyAll(); + }; + + dijit.byNode = function(node){ + // summary: + // Returns the widget corresponding to the given DOMNode + // node: DOMNode + return registry.byNode(node); // dijit._Widget + }; + + dijit.getEnclosingWidget = function(node){ + // summary: + // Returns the widget whose DOM tree contains the specified DOMNode, or null if + // the node is not contained within the DOM tree of any widget + // node: DOMNode + return registry.getEnclosingWidget(node); + }; + =====*/ + array.forEach(["byId", "getUniqueId", "findWidgets", "_destroyAll", "byNode", "getEnclosingWidget"], function(name){ + dijit[name] = registry[name]; + }); + + /*===== + dojo.mixin(dijit, { + // defaultDuration: Integer + // The default fx.animation speed (in ms) to use for all Dijit + // transitional fx.animations, unless otherwise specified + // on a per-instance basis. Defaults to 200, overrided by + // `djConfig.defaultDuration` + defaultDuration: 200 + }); + =====*/ + dijit.defaultDuration = config["defaultDuration"] || 200; + + return dijit; +}); + +}, +'dojox/charting/plot2d/StackedAreas':function(){ +define("dojox/charting/plot2d/StackedAreas", ["dojo/_base/declare", "./Stacked"], function(declare, Stacked){ +/*===== +var Stacked = dojox.charting.plot2d.Stacked; +=====*/ + return declare("dojox.charting.plot2d.StackedAreas", Stacked, { + // summary: + // A convenience object to set up a stacked area plot. + constructor: function(){ + // summary: + // Force our Stacked plotter to include both lines and areas. + this.opt.lines = true; + this.opt.areas = true; + } + }); +}); + + +}, +'dojox/charting/plot2d/Stacked':function(){ +define("dojox/charting/plot2d/Stacked", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "./Default", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/functional/sequence"], + function(lang, declare, arr, Default, dc, df, dfr, dfs){ +/*===== +var Default = dojox.charting.plot2d.Default; +=====*/ + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Stacked", Default, { + // summary: + // Like the default plot, Stacked sets up lines, areas and markers + // in a stacked fashion (values on the y axis added to each other) + // as opposed to a direct one. + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectStackedStats(this.series); + this._maxRunLength = stats.hmax; + return stats; + }, + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Stacked + // A reference to this plot for functional chaining. + if(this._maxRunLength <= 0){ + return this; + } + + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + } + // draw runs in backwards + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + + var t = this.chart.theme, events = this.events(), + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler); + + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next(this.opt.areas ? "area" : "line", [this.opt, run], true), + s = run.group, outline, + lpoly = arr.map(acc, function(v, i){ + return { + x: ht(i + 1) + offsets.l, + y: dim.height - offsets.b - vt(v) + }; + }, this); + + var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : ""; + + if(this.opt.areas){ + var apoly = lang.clone(lpoly); + if(this.opt.tension){ + var p=dc.curve(apoly, this.opt.tension); + p += " L" + lpoly[lpoly.length - 1].x + "," + (dim.height - offsets.b) + + " L" + lpoly[0].x + "," + (dim.height - offsets.b) + + " L" + lpoly[0].x + "," + lpoly[0].y; + run.dyn.fill = s.createPath(p).setFill(theme.series.fill).getFill(); + } else { + apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); + apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); + apoly.push(lpoly[0]); + run.dyn.fill = s.createPolyline(apoly).setFill(theme.series.fill).getFill(); + } + } + if(this.opt.lines || this.opt.markers){ + if(theme.series.outline){ + outline = dc.makeStroke(theme.series.outline); + outline.width = 2 * outline.width + theme.series.stroke.width; + } + } + if(this.opt.markers){ + run.dyn.marker = theme.symbol; + } + var frontMarkers, outlineMarkers, shadowMarkers; + if(theme.series.shadow && theme.series.stroke){ + var shadow = theme.series.shadow, + spoly = arr.map(lpoly, function(c){ + return {x: c.x + shadow.dx, y: c.y + shadow.dy}; + }); + if(this.opt.lines){ + if(this.opt.tension){ + run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadow).getStroke(); + } else { + run.dyn.shadow = s.createPolyline(spoly).setStroke(shadow).getStroke(); + } + } + if(this.opt.markers){ + shadow = theme.marker.shadow; + shadowMarkers = arr.map(spoly, function(c){ + return s.createPath("M" + c.x + " " + c.y + " " + theme.symbol). + setStroke(shadow).setFill(shadow.color); + }, this); + } + } + if(this.opt.lines){ + if(outline){ + if(this.opt.tension){ + run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke(); + } else { + run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke(); + } + } + if(this.opt.tension){ + run.dyn.stroke = s.createPath(lpath).setStroke(theme.series.stroke).getStroke(); + } else { + run.dyn.stroke = s.createPolyline(lpoly).setStroke(theme.series.stroke).getStroke(); + } + } + if(this.opt.markers){ + frontMarkers = new Array(lpoly.length); + outlineMarkers = new Array(lpoly.length); + outline = null; + if(theme.marker.outline){ + outline = dc.makeStroke(theme.marker.outline); + outline.width = 2 * outline.width + (theme.marker.stroke ? theme.marker.stroke.width : 0); + } + arr.forEach(lpoly, function(c, i){ + var path = "M" + c.x + " " + c.y + " " + theme.symbol; + if(outline){ + outlineMarkers[i] = s.createPath(path).setStroke(outline); + } + frontMarkers[i] = s.createPath(path).setStroke(theme.marker.stroke).setFill(theme.marker.fill); + }, this); + if(events){ + var eventSeries = new Array(frontMarkers.length); + arr.forEach(frontMarkers, function(s, i){ + var o = { + element: "marker", + index: i, + run: run, + shape: s, + outline: outlineMarkers[i] || null, + shadow: shadowMarkers && shadowMarkers[i] || null, + cx: lpoly[i].x, + cy: lpoly[i].y, + x: i + 1, + y: run.data[i] + }; + this._connectEvents(o); + eventSeries[i] = o; + }, this); + this._eventSeries[run.name] = eventSeries; + }else{ + delete this._eventSeries[run.name]; + } + } + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var v = run.data[j]; + if(v !== null){ + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + } + this.dirty = false; + return this; // dojox.charting.plot2d.Stacked + } + }); +}); + +}, +'dojo/fx/easing':function(){ +define(["../_base/lang"], function(lang) { +// module: +// dojo/fx/easing +// summary: +// This module defines standard easing functions that are useful for animations. + +var easingFuncs = /*===== dojo.fx.easing= =====*/ { + // summary: + // Collection of easing functions to use beyond the default + // `dojo._defaultEasing` function. + // + // description: + // + // Easing functions are used to manipulate the iteration through + // an `dojo.Animation`s _Line. _Line being the properties of an Animation, + // and the easing function progresses through that Line determing + // how quickly (or slowly) it should go. Or more accurately: modify + // the value of the _Line based on the percentage of animation completed. + // + // All functions follow a simple naming convention of "ease type" + "when". + // If the name of the function ends in Out, the easing described appears + // towards the end of the animation. "In" means during the beginning, + // and InOut means both ranges of the Animation will applied, both + // beginning and end. + // + // One does not call the easing function directly, it must be passed to + // the `easing` property of an animation. + // + // example: + // | dojo.require("dojo.fx.easing"); + // | var anim = dojo.fadeOut({ + // | node: 'node', + // | duration: 2000, + // | // note there is no () + // | easing: dojo.fx.easing.quadIn + // | }).play(); + // + + linear: function(/* Decimal? */n){ + // summary: A linear easing function + return n; + }, + + quadIn: function(/* Decimal? */n){ + return Math.pow(n, 2); + }, + + quadOut: function(/* Decimal? */n){ + return n * (n - 2) * -1; + }, + + quadInOut: function(/* Decimal? */n){ + n = n * 2; + if(n < 1){ return Math.pow(n, 2) / 2; } + return -1 * ((--n) * (n - 2) - 1) / 2; + }, + + cubicIn: function(/* Decimal? */n){ + return Math.pow(n, 3); + }, + + cubicOut: function(/* Decimal? */n){ + return Math.pow(n - 1, 3) + 1; + }, + + cubicInOut: function(/* Decimal? */n){ + n = n * 2; + if(n < 1){ return Math.pow(n, 3) / 2; } + n -= 2; + return (Math.pow(n, 3) + 2) / 2; + }, + + quartIn: function(/* Decimal? */n){ + return Math.pow(n, 4); + }, + + quartOut: function(/* Decimal? */n){ + return -1 * (Math.pow(n - 1, 4) - 1); + }, + + quartInOut: function(/* Decimal? */n){ + n = n * 2; + if(n < 1){ return Math.pow(n, 4) / 2; } + n -= 2; + return -1 / 2 * (Math.pow(n, 4) - 2); + }, + + quintIn: function(/* Decimal? */n){ + return Math.pow(n, 5); + }, + + quintOut: function(/* Decimal? */n){ + return Math.pow(n - 1, 5) + 1; + }, + + quintInOut: function(/* Decimal? */n){ + n = n * 2; + if(n < 1){ return Math.pow(n, 5) / 2; } + n -= 2; + return (Math.pow(n, 5) + 2) / 2; + }, + + sineIn: function(/* Decimal? */n){ + return -1 * Math.cos(n * (Math.PI / 2)) + 1; + }, + + sineOut: function(/* Decimal? */n){ + return Math.sin(n * (Math.PI / 2)); + }, + + sineInOut: function(/* Decimal? */n){ + return -1 * (Math.cos(Math.PI * n) - 1) / 2; + }, + + expoIn: function(/* Decimal? */n){ + return (n == 0) ? 0 : Math.pow(2, 10 * (n - 1)); + }, + + expoOut: function(/* Decimal? */n){ + return (n == 1) ? 1 : (-1 * Math.pow(2, -10 * n) + 1); + }, + + expoInOut: function(/* Decimal? */n){ + if(n == 0){ return 0; } + if(n == 1){ return 1; } + n = n * 2; + if(n < 1){ return Math.pow(2, 10 * (n - 1)) / 2; } + --n; + return (-1 * Math.pow(2, -10 * n) + 2) / 2; + }, + + circIn: function(/* Decimal? */n){ + return -1 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); + }, + + circOut: function(/* Decimal? */n){ + n = n - 1; + return Math.sqrt(1 - Math.pow(n, 2)); + }, + + circInOut: function(/* Decimal? */n){ + n = n * 2; + if(n < 1){ return -1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); } + n -= 2; + return 1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) + 1); + }, + + backIn: function(/* Decimal? */n){ + // summary: + // An easing function that starts away from the target, + // and quickly accelerates towards the end value. + // + // Use caution when the easing will cause values to become + // negative as some properties cannot be set to negative values. + var s = 1.70158; + return Math.pow(n, 2) * ((s + 1) * n - s); + }, + + backOut: function(/* Decimal? */n){ + // summary: + // An easing function that pops past the range briefly, and slowly comes back. + // + // description: + // An easing function that pops past the range briefly, and slowly comes back. + // + // Use caution when the easing will cause values to become negative as some + // properties cannot be set to negative values. + + n = n - 1; + var s = 1.70158; + return Math.pow(n, 2) * ((s + 1) * n + s) + 1; + }, + + backInOut: function(/* Decimal? */n){ + // summary: + // An easing function combining the effects of `backIn` and `backOut` + // + // description: + // An easing function combining the effects of `backIn` and `backOut`. + // Use caution when the easing will cause values to become negative + // as some properties cannot be set to negative values. + var s = 1.70158 * 1.525; + n = n * 2; + if(n < 1){ return (Math.pow(n, 2) * ((s + 1) * n - s)) / 2; } + n-=2; + return (Math.pow(n, 2) * ((s + 1) * n + s) + 2) / 2; + }, + + elasticIn: function(/* Decimal? */n){ + // summary: + // An easing function the elastically snaps from the start value + // + // description: + // An easing function the elastically snaps from the start value + // + // Use caution when the elasticity will cause values to become negative + // as some properties cannot be set to negative values. + if(n == 0 || n == 1){ return n; } + var p = .3; + var s = p / 4; + n = n - 1; + return -1 * Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p); + }, + + elasticOut: function(/* Decimal? */n){ + // summary: + // An easing function that elasticly snaps around the target value, + // near the end of the Animation + // + // description: + // An easing function that elasticly snaps around the target value, + // near the end of the Animation + // + // Use caution when the elasticity will cause values to become + // negative as some properties cannot be set to negative values. + if(n==0 || n == 1){ return n; } + var p = .3; + var s = p / 4; + return Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p) + 1; + }, + + elasticInOut: function(/* Decimal? */n){ + // summary: + // An easing function that elasticly snaps around the value, near + // the beginning and end of the Animation. + // + // description: + // An easing function that elasticly snaps around the value, near + // the beginning and end of the Animation. + // + // Use caution when the elasticity will cause values to become + // negative as some properties cannot be set to negative values. + if(n == 0) return 0; + n = n * 2; + if(n == 2) return 1; + var p = .3 * 1.5; + var s = p / 4; + if(n < 1){ + n -= 1; + return -.5 * (Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p)); + } + n -= 1; + return .5 * (Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p)) + 1; + }, + + bounceIn: function(/* Decimal? */n){ + // summary: + // An easing function that 'bounces' near the beginning of an Animation + return (1 - easingFuncs.bounceOut(1 - n)); // Decimal + }, + + bounceOut: function(/* Decimal? */n){ + // summary: + // An easing function that 'bounces' near the end of an Animation + var s = 7.5625; + var p = 2.75; + var l; + if(n < (1 / p)){ + l = s * Math.pow(n, 2); + }else if(n < (2 / p)){ + n -= (1.5 / p); + l = s * Math.pow(n, 2) + .75; + }else if(n < (2.5 / p)){ + n -= (2.25 / p); + l = s * Math.pow(n, 2) + .9375; + }else{ + n -= (2.625 / p); + l = s * Math.pow(n, 2) + .984375; + } + return l; + }, + + bounceInOut: function(/* Decimal? */n){ + // summary: + // An easing function that 'bounces' at the beginning and end of the Animation + if(n < 0.5){ return easingFuncs.bounceIn(n * 2) / 2; } + return (easingFuncs.bounceOut(n * 2 - 1) / 2) + 0.5; // Decimal + } +}; + +lang.setObject("dojo.fx.easing", easingFuncs); + +return easingFuncs; +}); + +}, +'dojox/charting/action2d/Highlight':function(){ +define("dojox/charting/action2d/Highlight", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/Color", "dojo/_base/connect", "dojox/color/_base", + "./PlotAction", "dojo/fx/easing", "dojox/gfx/fx"], + function(dojo, lang, declare, Color, hub, c, PlotAction, dfe, dgf){ + + /*===== + dojo.declare("dojox.charting.action2d.__HighlightCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // highlight: String|dojo.Color|Function? + // Either a color or a function that creates a color when highlighting happens. + highlight: null + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SATURATION = 100, // % + DEFAULT_LUMINOSITY1 = 75, // % + DEFAULT_LUMINOSITY2 = 50, // % + cc = function(color){ + return function(){ return color; }; + }, + + hl = function(color){ + var a = new c.Color(color), + x = a.toHsl(); + if(x.s == 0){ + x.l = x.l < 50 ? 100 : 0; + }else{ + x.s = DEFAULT_SATURATION; + if(x.l < DEFAULT_LUMINOSITY2){ + x.l = DEFAULT_LUMINOSITY1; + }else if(x.l > DEFAULT_LUMINOSITY1){ + x.l = DEFAULT_LUMINOSITY2; + }else{ + x.l = x.l - DEFAULT_LUMINOSITY2 > DEFAULT_LUMINOSITY1 - x.l ? + DEFAULT_LUMINOSITY2 : DEFAULT_LUMINOSITY1; + } + } + return c.fromHsl(x); + }; + + return declare("dojox.charting.action2d.Highlight", PlotAction, { + // summary: + // Creates a highlighting action on a plot, where an element on that plot + // has a highlight on it. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut // easing for the action + }, + optionalParams: { + highlight: "red" // name for the highlight color + // programmatic instantiation can use functions and color objects + }, + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the highlighting action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: charting.action2d.__HighlightCtorArgs? + // Optional keyword arguments object for setting parameters. + var a = kwArgs && kwArgs.highlight; + this.colorFun = a ? (lang.isFunction(a) ? a : cc(a)) : hl; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the highlighting action. + if(!o.shape || !(o.type in this.overOutEvents)){ return; } + + var runName = o.run.name, index = o.index, anim, startFill, endFill; + + if(runName in this.anim){ + anim = this.anim[runName][index]; + }else{ + this.anim[runName] = {}; + } + + if(anim){ + anim.action.stop(true); + }else{ + var color = o.shape.getFill(); + if(!color || !(color instanceof Color)){ + return; + } + this.anim[runName][index] = anim = { + start: color, + end: this.colorFun(color) + }; + } + + var start = anim.start, end = anim.end; + if(o.type == "onmouseout"){ + // swap colors + var t = start; + start = end; + end = t; + } + + anim.action = dgf.animateFill({ + shape: o.shape, + duration: this.duration, + easing: this.easing, + color: {start: start, end: end} + }); + if(o.type == "onmouseout"){ + hub.connect(anim.action, "onEnd", this, function(){ + if(this.anim[runName]){ + delete this.anim[runName][index]; + } + }); + } + anim.action.play(); + } + }); + +}); + +}, +'dojox/color/Palette':function(){ +define("dojox/color/Palette", ["dojo/_base/kernel", "../main", "dojo/_base/lang", "dojo/_base/array", "./_base"], + function(dojo, dojox, lang, arr, dxc){ + + /*************************************************************** + * dojox.color.Palette + * + * The Palette object is loosely based on the color palettes + * at Kuler (http://kuler.adobe.com). They are 5 color palettes + * with the base color considered to be the third color in the + * palette (for generation purposes). + * + * Palettes can be generated from well-known algorithms or they + * can be manually created by passing an array to the constructor. + * + * Palettes can be transformed, using a set of specific params + * similar to the way shapes can be transformed with dojox.gfx. + * However, unlike with transformations in dojox.gfx, transforming + * a palette will return you a new Palette object, in effect + * a clone of the original. + ***************************************************************/ + + // ctor ---------------------------------------------------------------------------- + dxc.Palette = function(/* String|Array|dojox.color.Color|dojox.color.Palette */base){ + // summary: + // An object that represents a palette of colors. + // description: + // A Palette is a representation of a set of colors. While the standard + // number of colors contained in a palette is 5, it can really handle any + // number of colors. + // + // A palette is useful for the ability to transform all the colors in it + // using a simple object-based approach. In addition, you can generate + // palettes using dojox.color.Palette.generate; these generated palettes + // are based on the palette generators at http://kuler.adobe.com. + // + // colors: dojox.color.Color[] + // The actual color references in this palette. + this.colors = []; + if(base instanceof dxc.Palette){ + this.colors = base.colors.slice(0); + } + else if(base instanceof dxc.Color){ + this.colors = [ null, null, base, null, null ]; + } + else if(lang.isArray(base)){ + this.colors = arr.map(base.slice(0), function(item){ + if(lang.isString(item)){ return new dxc.Color(item); } + return item; + }); + } + else if (lang.isString(base)){ + this.colors = [ null, null, new dxc.Color(base), null, null ]; + } + } + + // private functions --------------------------------------------------------------- + + // transformations + function tRGBA(p, param, val){ + var ret = new dxc.Palette(); + ret.colors = []; + arr.forEach(p.colors, function(item){ + var r=(param=="dr")?item.r+val:item.r, + g=(param=="dg")?item.g+val:item.g, + b=(param=="db")?item.b+val:item.b, + a=(param=="da")?item.a+val:item.a + ret.colors.push(new dxc.Color({ + r: Math.min(255, Math.max(0, r)), + g: Math.min(255, Math.max(0, g)), + b: Math.min(255, Math.max(0, b)), + a: Math.min(1, Math.max(0, a)) + })); + }); + return ret; + } + + function tCMY(p, param, val){ + var ret = new dxc.Palette(); + ret.colors = []; + arr.forEach(p.colors, function(item){ + var o=item.toCmy(), + c=(param=="dc")?o.c+val:o.c, + m=(param=="dm")?o.m+val:o.m, + y=(param=="dy")?o.y+val:o.y; + ret.colors.push(dxc.fromCmy( + Math.min(100, Math.max(0, c)), + Math.min(100, Math.max(0, m)), + Math.min(100, Math.max(0, y)) + )); + }); + return ret; + } + + function tCMYK(p, param, val){ + var ret = new dxc.Palette(); + ret.colors = []; + arr.forEach(p.colors, function(item){ + var o=item.toCmyk(), + c=(param=="dc")?o.c+val:o.c, + m=(param=="dm")?o.m+val:o.m, + y=(param=="dy")?o.y+val:o.y, + k=(param=="dk")?o.b+val:o.b; + ret.colors.push(dxc.fromCmyk( + Math.min(100, Math.max(0, c)), + Math.min(100, Math.max(0, m)), + Math.min(100, Math.max(0, y)), + Math.min(100, Math.max(0, k)) + )); + }); + return ret; + } + + function tHSL(p, param, val){ + var ret = new dxc.Palette(); + ret.colors = []; + arr.forEach(p.colors, function(item){ + var o=item.toHsl(), + h=(param=="dh")?o.h+val:o.h, + s=(param=="ds")?o.s+val:o.s, + l=(param=="dl")?o.l+val:o.l; + ret.colors.push(dxc.fromHsl(h%360, Math.min(100, Math.max(0, s)), Math.min(100, Math.max(0, l)))); + }); + return ret; + } + + function tHSV(p, param, val){ + var ret = new dxc.Palette(); + ret.colors = []; + arr.forEach(p.colors, function(item){ + var o=item.toHsv(), + h=(param=="dh")?o.h+val:o.h, + s=(param=="ds")?o.s+val:o.s, + v=(param=="dv")?o.v+val:o.v; + ret.colors.push(dxc.fromHsv(h%360, Math.min(100, Math.max(0, s)), Math.min(100, Math.max(0, v)))); + }); + return ret; + } + + // helper functions + function rangeDiff(val, low, high){ + // given the value in a range from 0 to high, find the equiv + // using the range low to high. + return high-((high-val)*((high-low)/high)); + } + + // object methods --------------------------------------------------------------- + lang.extend(dxc.Palette, { + transform: function(/* dojox.color.Palette.__transformArgs */kwArgs){ + // summary: + // Transform the palette using a specific transformation function + // and a set of transformation parameters. + // description: + // {palette}.transform is a simple way to uniformly transform + // all of the colors in a palette using any of 5 formulae: + // RGBA, HSL, HSV, CMYK or CMY. + // + // Once the forumula to be used is determined, you can pass any + // number of parameters based on the formula "d"[param]; for instance, + // { use: "rgba", dr: 20, dg: -50 } will take all of the colors in + // palette, add 20 to the R value and subtract 50 from the G value. + // + // Unlike other types of transformations, transform does *not* alter + // the original palette but will instead return a new one. + var fn=tRGBA; // the default transform function. + if(kwArgs.use){ + // we are being specific about the algo we want to use. + var use=kwArgs.use.toLowerCase(); + if(use.indexOf("hs")==0){ + if(use.charAt(2)=="l"){ fn=tHSL; } + else { fn=tHSV; } + } + else if(use.indexOf("cmy")==0){ + if(use.charAt(3)=="k"){ fn=tCMYK; } + else { fn=tCMY; } + } + } + // try to guess the best choice. + else if("dc" in kwArgs || "dm" in kwArgs || "dy" in kwArgs){ + if("dk" in kwArgs){ fn = tCMYK; } + else { fn = tCMY; } + } + else if("dh" in kwArgs || "ds" in kwArgs){ + if("dv" in kwArgs){ fn = tHSV; } + else { fn = tHSL; } + } + + var palette = this; + for(var p in kwArgs){ + // ignore use + if(p=="use"){ continue; } + palette = fn(palette, p, kwArgs[p]); + } + return palette; // dojox.color.Palette + }, + clone: function(){ + // summary: + // Clones the current palette. + return new dxc.Palette(this); // dojox.color.Palette + } + }); + +/*===== +dojox.color.Palette.__transformArgs = function(use, dr, dg, db, da, dc, dm, dy, dk, dh, ds, dv, dl){ + // summary: + // The keywords argument to be passed to the dojox.color.Palette.transform function. Note that + // while all arguments are optional, *some* arguments must be passed. The basic concept is that + // you pass a delta value for a specific aspect of a color model (or multiple aspects of the same + // color model); for instance, if you wish to transform a palette based on the HSV color model, + // you would pass one of "dh", "ds", or "dv" as a value. + // + // use: String? + // Specify the color model to use for the transformation. Can be "rgb", "rgba", "hsv", "hsl", "cmy", "cmyk". + // dr: Number? + // The delta to be applied to the red aspect of the RGB/RGBA color model. + // dg: Number? + // The delta to be applied to the green aspect of the RGB/RGBA color model. + // db: Number? + // The delta to be applied to the blue aspect of the RGB/RGBA color model. + // da: Number? + // The delta to be applied to the alpha aspect of the RGBA color model. + // dc: Number? + // The delta to be applied to the cyan aspect of the CMY/CMYK color model. + // dm: Number? + // The delta to be applied to the magenta aspect of the CMY/CMYK color model. + // dy: Number? + // The delta to be applied to the yellow aspect of the CMY/CMYK color model. + // dk: Number? + // The delta to be applied to the black aspect of the CMYK color model. + // dh: Number? + // The delta to be applied to the hue aspect of the HSL/HSV color model. + // ds: Number? + // The delta to be applied to the saturation aspect of the HSL/HSV color model. + // dl: Number? + // The delta to be applied to the luminosity aspect of the HSL color model. + // dv: Number? + // The delta to be applied to the value aspect of the HSV color model. + this.use = use; + this.dr = dr; + this.dg = dg; + this.db = db; + this.da = da; + this.dc = dc; + this.dm = dm; + this.dy = dy; + this.dk = dk; + this.dh = dh; + this.ds = ds; + this.dl = dl; + this.dv = dv; +} +dojox.color.Palette.__generatorArgs = function(base){ + // summary: + // The keyword arguments object used to create a palette based on a base color. + // + // base: dojo.Color + // The base color to be used to generate the palette. + this.base = base; +} +dojox.color.Palette.__analogousArgs = function(base, high, low){ + // summary: + // The keyword arguments object that is used to create a 5 color palette based on the + // analogous rules as implemented at http://kuler.adobe.com, using the HSV color model. + // + // base: dojo.Color + // The base color to be used to generate the palette. + // high: Number? + // The difference between the hue of the base color and the highest hue. In degrees, default is 60. + // low: Number? + // The difference between the hue of the base color and the lowest hue. In degrees, default is 18. + this.base = base; + this.high = high; + this.low = low; +} +dojox.color.Palette.__splitComplementaryArgs = function(base, da){ + // summary: + // The keyword arguments object used to create a palette based on the split complementary rules + // as implemented at http://kuler.adobe.com. + // + // base: dojo.Color + // The base color to be used to generate the palette. + // da: Number? + // The delta angle to be used to determine where the split for the complementary rules happen. + // In degrees, the default is 30. + this.base = base; + this.da = da; +} +=====*/ + lang.mixin(dxc.Palette, { + generators: { + analogous:function(/* dojox.color.Palette.__analogousArgs */args){ + // summary: + // Create a 5 color palette based on the analogous rules as implemented at + // http://kuler.adobe.com. + var high=args.high||60, // delta between base hue and highest hue (subtracted from base) + low=args.low||18, // delta between base hue and lowest hue (added to base) + base = lang.isString(args.base)?new dxc.Color(args.base):args.base, + hsv=base.toHsv(); + + // generate our hue angle differences + var h=[ + (hsv.h+low+360)%360, + (hsv.h+Math.round(low/2)+360)%360, + hsv.h, + (hsv.h-Math.round(high/2)+360)%360, + (hsv.h-high+360)%360 + ]; + + var s1=Math.max(10, (hsv.s<=95)?hsv.s+5:(100-(hsv.s-95))), + s2=(hsv.s>1)?hsv.s-1:21-hsv.s, + v1=(hsv.v>=92)?hsv.v-9:Math.max(hsv.v+9, 20), + v2=(hsv.v<=90)?Math.max(hsv.v+5, 20):(95+Math.ceil((hsv.v-90)/2)), + s=[ s1, s2, hsv.s, s1, s1 ], + v=[ v1, v2, hsv.v, v1, v2 ] + + return new dxc.Palette(arr.map(h, function(hue, i){ + return dxc.fromHsv(hue, s[i], v[i]); + })); // dojox.color.Palette + }, + + monochromatic: function(/* dojox.color.Palette.__generatorArgs */args){ + // summary: + // Create a 5 color palette based on the monochromatic rules as implemented at + // http://kuler.adobe.com. + var base = lang.isString(args.base)?new dxc.Color(args.base):args.base, + hsv = base.toHsv(); + + // figure out the saturation and value + var s1 = (hsv.s-30>9)?hsv.s-30:hsv.s+30, + s2 = hsv.s, + v1 = rangeDiff(hsv.v, 20, 100), + v2 = (hsv.v-20>20)?hsv.v-20:hsv.v+60, + v3 = (hsv.v-50>20)?hsv.v-50:hsv.v+30; + + return new dxc.Palette([ + dxc.fromHsv(hsv.h, s1, v1), + dxc.fromHsv(hsv.h, s2, v3), + base, + dxc.fromHsv(hsv.h, s1, v3), + dxc.fromHsv(hsv.h, s2, v2) + ]); // dojox.color.Palette + }, + + triadic: function(/* dojox.color.Palette.__generatorArgs */args){ + // summary: + // Create a 5 color palette based on the triadic rules as implemented at + // http://kuler.adobe.com. + var base = lang.isString(args.base)?new dxc.Color(args.base):args.base, + hsv = base.toHsv(); + + var h1 = (hsv.h+57+360)%360, + h2 = (hsv.h-157+360)%360, + s1 = (hsv.s>20)?hsv.s-10:hsv.s+10, + s2 = (hsv.s>90)?hsv.s-10:hsv.s+10, + s3 = (hsv.s>95)?hsv.s-5:hsv.s+5, + v1 = (hsv.v-20>20)?hsv.v-20:hsv.v+20, + v2 = (hsv.v-30>20)?hsv.v-30:hsv.v+30, + v3 = (hsv.v-30>70)?hsv.v-30:hsv.v+30; + + return new dxc.Palette([ + dxc.fromHsv(h1, s1, hsv.v), + dxc.fromHsv(hsv.h, s2, v2), + base, + dxc.fromHsv(h2, s2, v1), + dxc.fromHsv(h2, s3, v3) + ]); // dojox.color.Palette + }, + + complementary: function(/* dojox.color.Palette.__generatorArgs */args){ + // summary: + // Create a 5 color palette based on the complementary rules as implemented at + // http://kuler.adobe.com. + var base = lang.isString(args.base)?new dxc.Color(args.base):args.base, + hsv = base.toHsv(); + + var h1 = ((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137, + s1 = Math.max(hsv.s-10, 0), + s2 = rangeDiff(hsv.s, 10, 100), + s3 = Math.min(100, hsv.s+20), + v1 = Math.min(100, hsv.v+30), + v2 = (hsv.v>20)?hsv.v-30:hsv.v+30; + + return new dxc.Palette([ + dxc.fromHsv(hsv.h, s1, v1), + dxc.fromHsv(hsv.h, s2, v2), + base, + dxc.fromHsv(h1, s3, v2), + dxc.fromHsv(h1, hsv.s, hsv.v) + ]); // dojox.color.Palette + }, + + splitComplementary: function(/* dojox.color.Palette.__splitComplementaryArgs */args){ + // summary: + // Create a 5 color palette based on the split complementary rules as implemented at + // http://kuler.adobe.com. + var base = lang.isString(args.base)?new dxc.Color(args.base):args.base, + dangle = args.da || 30, + hsv = base.toHsv(); + + var baseh = ((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137, + h1 = (baseh-dangle+360)%360, + h2 = (baseh+dangle)%360, + s1 = Math.max(hsv.s-10, 0), + s2 = rangeDiff(hsv.s, 10, 100), + s3 = Math.min(100, hsv.s+20), + v1 = Math.min(100, hsv.v+30), + v2 = (hsv.v>20)?hsv.v-30:hsv.v+30; + + return new dxc.Palette([ + dxc.fromHsv(h1, s1, v1), + dxc.fromHsv(h1, s2, v2), + base, + dxc.fromHsv(h2, s3, v2), + dxc.fromHsv(h2, hsv.s, hsv.v) + ]); // dojox.color.Palette + }, + + compound: function(/* dojox.color.Palette.__generatorArgs */args){ + // summary: + // Create a 5 color palette based on the compound rules as implemented at + // http://kuler.adobe.com. + var base = lang.isString(args.base)?new dxc.Color(args.base):args.base, + hsv = base.toHsv(); + + var h1 = ((hsv.h*2)+18<360)?(hsv.h*2)+18:Math.floor(hsv.h/2)-18, + h2 = ((hsv.h*2)+120<360)?(hsv.h*2)+120:Math.floor(hsv.h/2)-120, + h3 = ((hsv.h*2)+99<360)?(hsv.h*2)+99:Math.floor(hsv.h/2)-99, + s1 = (hsv.s-40>10)?hsv.s-40:hsv.s+40, + s2 = (hsv.s-10>80)?hsv.s-10:hsv.s+10, + s3 = (hsv.s-25>10)?hsv.s-25:hsv.s+25, + v1 = (hsv.v-40>10)?hsv.v-40:hsv.v+40, + v2 = (hsv.v-20>80)?hsv.v-20:hsv.v+20, + v3 = Math.max(hsv.v, 20); + + return new dxc.Palette([ + dxc.fromHsv(h1, s1, v1), + dxc.fromHsv(h1, s2, v2), + base, + dxc.fromHsv(h2, s3, v3), + dxc.fromHsv(h3, s2, v2) + ]); // dojox.color.Palette + }, + + shades: function(/* dojox.color.Palette.__generatorArgs */args){ + // summary: + // Create a 5 color palette based on the shades rules as implemented at + // http://kuler.adobe.com. + var base = lang.isString(args.base)?new dxc.Color(args.base):args.base, + hsv = base.toHsv(); + + var s = (hsv.s==100 && hsv.v==0)?0:hsv.s, + v1 = (hsv.v-50>20)?hsv.v-50:hsv.v+30, + v2 = (hsv.v-25>=20)?hsv.v-25:hsv.v+55, + v3 = (hsv.v-75>=20)?hsv.v-75:hsv.v+5, + v4 = Math.max(hsv.v-10, 20); + + return new dxc.Palette([ + new dxc.fromHsv(hsv.h, s, v1), + new dxc.fromHsv(hsv.h, s, v2), + base, + new dxc.fromHsv(hsv.h, s, v3), + new dxc.fromHsv(hsv.h, s, v4) + ]); // dojox.color.Palette + } + }, + generate: function(/* String|dojox.color.Color */base, /* Function|String */type){ + // summary: + // Generate a new Palette using any of the named functions in + // dojox.color.Palette.generators or an optional function definition. Current + // generators include "analogous", "monochromatic", "triadic", "complementary", + // "splitComplementary", and "shades". + if(lang.isFunction(type)){ + return type({ base: base }); // dojox.color.Palette + } + else if(dxc.Palette.generators[type]){ + return dxc.Palette.generators[type]({ base: base }); // dojox.color.Palette + } + throw new Error("dojox.color.Palette.generate: the specified generator ('" + type + "') does not exist."); + } + }); + + return dxc.Palette; +}); + +}, +'dijit/a11y':function(){ +define("dijit/a11y", [ + "dojo/_base/array", // array.forEach array.map + "dojo/_base/config", // defaultDuration + "dojo/_base/declare", // declare + "dojo/dom", // dom.byId + "dojo/dom-attr", // domAttr.attr domAttr.has + "dojo/dom-style", // style.style + "dojo/_base/sniff", // has("ie") + "./_base/manager", // manager._isElementShown + "." // for exporting methods to dijit namespace +], function(array, config, declare, dom, domAttr, domStyle, has, manager, dijit){ + + // module: + // dijit/a11y + // summary: + // Accessibility utility functions (keyboard, tab stops, etc.) + + var shown = (dijit._isElementShown = function(/*Element*/ elem){ + var s = domStyle.get(elem); + return (s.visibility != "hidden") + && (s.visibility != "collapsed") + && (s.display != "none") + && (domAttr.get(elem, "type") != "hidden"); + }); + + dijit.hasDefaultTabStop = function(/*Element*/ elem){ + // summary: + // Tests if element is tab-navigable even without an explicit tabIndex setting + + // No explicit tabIndex setting, need to investigate node type + switch(elem.nodeName.toLowerCase()){ + case "a": + // An <a> w/out a tabindex is only navigable if it has an href + return domAttr.has(elem, "href"); + case "area": + case "button": + case "input": + case "object": + case "select": + case "textarea": + // These are navigable by default + return true; + case "iframe": + // If it's an editor <iframe> then it's tab navigable. + var body; + try{ + // non-IE + var contentDocument = elem.contentDocument; + if("designMode" in contentDocument && contentDocument.designMode == "on"){ + return true; + } + body = contentDocument.body; + }catch(e1){ + // contentWindow.document isn't accessible within IE7/8 + // if the iframe.src points to a foreign url and this + // page contains an element, that could get focus + try{ + body = elem.contentWindow.document.body; + }catch(e2){ + return false; + } + } + return body && (body.contentEditable == 'true' || + (body.firstChild && body.firstChild.contentEditable == 'true')); + default: + return elem.contentEditable == 'true'; + } + }; + + var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){ + // summary: + // Tests if an element is tab-navigable + + // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable() + if(domAttr.get(elem, "disabled")){ + return false; + }else if(domAttr.has(elem, "tabIndex")){ + // Explicit tab index setting + return domAttr.get(elem, "tabIndex") >= 0; // boolean + }else{ + // No explicit tabIndex setting, so depends on node type + return dijit.hasDefaultTabStop(elem); + } + }); + + dijit._getTabNavigable = function(/*DOMNode*/ root){ + // summary: + // Finds descendants of the specified root node. + // + // description: + // Finds the following descendants of the specified root node: + // * the first tab-navigable element in document order + // without a tabIndex or with tabIndex="0" + // * the last tab-navigable element in document order + // without a tabIndex or with tabIndex="0" + // * the first element in document order with the lowest + // positive tabIndex value + // * the last element in document order with the highest + // positive tabIndex value + var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {}; + + function radioName(node){ + // If this element is part of a radio button group, return the name for that group. + return node && node.tagName.toLowerCase() == "input" && + node.type && node.type.toLowerCase() == "radio" && + node.name && node.name.toLowerCase(); + } + + var walkTree = function(/*DOMNode*/parent){ + for(var child = parent.firstChild; child; child = child.nextSibling){ + // Skip text elements, hidden elements, and also non-HTML elements (those in custom namespaces) in IE, + // since show() invokes getAttribute("type"), which crash on VML nodes in IE. + if(child.nodeType != 1 || (has("ie") && child.scopeName !== "HTML") || !shown(child)){ + continue; + } + + if(isTabNavigable(child)){ + var tabindex = domAttr.get(child, "tabIndex"); + if(!domAttr.has(child, "tabIndex") || tabindex == 0){ + if(!first){ + first = child; + } + last = child; + }else if(tabindex > 0){ + if(!lowest || tabindex < lowestTabindex){ + lowestTabindex = tabindex; + lowest = child; + } + if(!highest || tabindex >= highestTabindex){ + highestTabindex = tabindex; + highest = child; + } + } + var rn = radioName(child); + if(domAttr.get(child, "checked") && rn){ + radioSelected[rn] = child; + } + } + if(child.nodeName.toUpperCase() != 'SELECT'){ + walkTree(child); + } + } + }; + if(shown(root)){ + walkTree(root); + } + function rs(node){ + // substitute checked radio button for unchecked one, if there is a checked one with the same name. + return radioSelected[radioName(node)] || node; + } + + return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) }; + }; + dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){ + // summary: + // Finds the descendant of the specified root node + // that is first in the tabbing order + var elems = dijit._getTabNavigable(dom.byId(root)); + return elems.lowest ? elems.lowest : elems.first; // DomNode + }; + + dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){ + // summary: + // Finds the descendant of the specified root node + // that is last in the tabbing order + var elems = dijit._getTabNavigable(dom.byId(root)); + return elems.last ? elems.last : elems.highest; // DomNode + }; + + return { + hasDefaultTabStop: dijit.hasDefaultTabStop, + isTabNavigable: dijit.isTabNavigable, + _getTabNavigable: dijit._getTabNavigable, + getFirstInTabbingOrder: dijit.getFirstInTabbingOrder, + getLastInTabbingOrder: dijit.getLastInTabbingOrder + }; +}); + +}, +'dojox/charting/axis2d/Base':function(){ +define("dojox/charting/axis2d/Base", ["dojo/_base/declare", "../Element"], + function(declare, Element){ +/*===== +var Element = dojox.charting.Element; +=====*/ +return declare("dojox.charting.axis2d.Base", Element, { + // summary: + // The base class for any axis. This is more of an interface/API + // definition than anything else; see dojox.charting.axis2d.Default + // for more details. + constructor: function(chart, kwArgs){ + // summary: + // Return a new base axis. + // chart: dojox.charting.Chart + // The chart this axis belongs to. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // An optional arguments object to define the axis parameters. + this.vertical = kwArgs && kwArgs.vertical; + }, + clear: function(){ + // summary: + // Stub function for clearing the axis. + // returns: dojox.charting.axis2d.Base + // A reference to the axis for functional chaining. + return this; // dojox.charting.axis2d.Base + }, + initialized: function(){ + // summary: + // Return a flag as to whether or not this axis has been initialized. + // returns: Boolean + // If the axis is initialized or not. + return false; // Boolean + }, + calculate: function(min, max, span){ + // summary: + // Stub function to run the calcuations needed for drawing this axis. + // returns: dojox.charting.axis2d.Base + // A reference to the axis for functional chaining. + return this; // dojox.charting.axis2d.Base + }, + getScaler: function(){ + // summary: + // A stub function to return the scaler object created during calculate. + // returns: Object + // The scaler object (see dojox.charting.scaler.linear for more information) + return null; // Object + }, + getTicks: function(){ + // summary: + // A stub function to return the object that helps define how ticks are rendered. + // returns: Object + // The ticks object. + return null; // Object + }, + getOffsets: function(){ + // summary: + // A stub function to return any offsets needed for axis and series rendering. + // returns: Object + // An object of the form { l, r, t, b }. + return {l: 0, r: 0, t: 0, b: 0}; // Object + }, + render: function(dim, offsets){ + // summary: + // Stub function to render this axis. + // returns: dojox.charting.axis2d.Base + // A reference to the axis for functional chaining. + this.dirty = false; + return this; // dojox.charting.axis2d.Base + } +}); +}); + +}, +'dojox/charting/plot2d/Grid':function(){ +define("dojox/charting/plot2d/Grid", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/array", + "../Element", "./common", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, hub, arr, Element, dc, du, fx){ + + /*===== + dojo.declare("dojox.charting.plot2d.__GridCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { + // summary: + // A special keyword arguments object that is specific to a grid "plot". + + // hMajorLines: Boolean? + // Whether to show lines at the major ticks along the horizontal axis. Default is true. + hMajorLines: true, + + // hMinorLines: Boolean? + // Whether to show lines at the minor ticks along the horizontal axis. Default is false. + hMinorLines: false, + + // vMajorLines: Boolean? + // Whether to show lines at the major ticks along the vertical axis. Default is true. + vMajorLines: true, + + // vMinorLines: Boolean? + // Whether to show lines at the major ticks along the vertical axis. Default is false. + vMinorLines: false, + + // hStripes: String? + // Whether or not to show stripes (alternating fills) along the horizontal axis. Default is "none". + hStripes: "none", + + // vStripes: String? + // Whether or not to show stripes (alternating fills) along the vertical axis. Default is "none". + vStripes: "none", + + // enableCache: Boolean? + // Whether the grid lines are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. Default false. + enableCache: false + }); + var Element = dojox.charting.plot2d.Element; + =====*/ + + return declare("dojox.charting.plot2d.Grid", Element, { + // summary: + // A "faux" plot that can be placed behind other plots to represent + // a grid against which other plots can be easily measured. + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + hMajorLines: true, // draw horizontal major lines + hMinorLines: false, // draw horizontal minor lines + vMajorLines: true, // draw vertical major lines + vMinorLines: false, // draw vertical minor lines + hStripes: "none", // TBD + vStripes: "none", // TBD + animate: null, // animate bars into place + enableCache: false + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, kwArgs){ + // summary: + // Create the faux Grid plot. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__GridCtorArgs? + // An optional keyword arguments object to help define the parameters of the underlying grid. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.dirty = true; + this.animate = this.opt.animate; + this.zoom = null, + this.zoomQueue = []; // zooming action task queue + this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0}; + if(this.opt.enableCache){ + this._lineFreePool = []; + this._lineUsePool = []; + } + }, + clear: function(){ + // summary: + // Clear out any parameters set on this plot. + // returns: dojox.charting.plot2d.Grid + // The reference to this plot for functional chaining. + this._hAxis = null; + this._vAxis = null; + this.dirty = true; + return this; // dojox.charting.plot2d.Grid + }, + setAxis: function(axis){ + // summary: + // Set an axis for this plot. + // returns: dojox.charting.plot2d.Grid + // The reference to this plot for functional chaining. + if(axis){ + this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; + } + return this; // dojox.charting.plot2d.Grid + }, + addSeries: function(run){ + // summary: + // Ignored but included as a dummy method. + // returns: dojox.charting.plot2d.Grid + // The reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Grid + }, + getSeriesStats: function(){ + // summary: + // Returns default stats (irrelevant for this type of plot). + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return lang.delegate(dc.defaultStats); + }, + initializeScalers: function(){ + // summary: + // Does nothing (irrelevant for this type of plot). + return this; + }, + isDirty: function(){ + // summary: + // Return whether or not this plot needs to be redrawn. + // returns: Boolean + // If this plot needs to be rendered, this will return true. + return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean + }, + performZoom: function(dim, offsets){ + // summary: + // Create/alter any zooming windows on this plot. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Grid + // A reference to this plot for functional chaining. + + // get current zooming various + var vs = this._vAxis.scale || 1, + hs = this._hAxis.scale || 1, + vOffset = dim.height - offsets.b, + hBounds = this._hAxis.getScaler().bounds, + xOffset = (hBounds.from - hBounds.lower) * hBounds.scale, + vBounds = this._vAxis.getScaler().bounds, + yOffset = (vBounds.from - vBounds.lower) * vBounds.scale, + // get incremental zooming various + rVScale = vs / this.lastWindow.vscale, + rHScale = hs / this.lastWindow.hscale, + rXOffset = (this.lastWindow.xoffset - xOffset)/ + ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale), + rYOffset = (yOffset - this.lastWindow.yoffset)/ + ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale), + + shape = this.group, + anim = fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform:[ + {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]}, + {name:"scale", start:[1, 1], end: [rHScale, rVScale]}, + {name:"original"}, + {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]} + ]}, this.zoom)); + + lang.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset}); + //add anim to zooming action queue, + //in order to avoid several zooming action happened at the same time + this.zoomQueue.push(anim); + //perform each anim one by one in zoomQueue + hub.connect(anim, "onEnd", this, function(){ + this.zoom = null; + this.zoomQueue.shift(); + if(this.zoomQueue.length > 0){ + this.zoomQueue[0].play(); + } + }); + if(this.zoomQueue.length == 1){ + this.zoomQueue[0].play(); + } + return this; // dojox.charting.plot2d.Grid + }, + getRequiredColors: function(){ + // summary: + // Ignored but included as a dummy method. + // returns: Number + // Returns 0, since there are no series associated with this plot type. + return 0; // Number + }, + cleanGroup: function(){ + this.inherited(arguments); + if(this.opt.enableCache){ + this._lineFreePool = this._lineFreePool.concat(this._lineUsePool); + this._lineUsePool = []; + } + }, + createLine: function(creator, params){ + var line; + if(this.opt.enableCache && this._lineFreePool.length > 0){ + line = this._lineFreePool.pop(); + line.setShape(params); + // was cleared, add it back + creator.add(line); + }else{ + line = creator.createLine(params); + } + if(this.opt.enableCache){ + this._lineUsePool.push(line); + } + return line; + }, + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Grid + // A reference to this plot for functional chaining. + if(this.zoom){ + return this.performZoom(dim, offsets); + } + this.dirty = this.isDirty(); + if(!this.dirty){ return this; } + this.cleanGroup(); + var s = this.group, ta = this.chart.theme.axis; + // draw horizontal stripes and lines + try{ + var vScaler = this._vAxis.getScaler(), + vt = vScaler.scaler.getTransformerFromModel(vScaler), + ticks = this._vAxis.getTicks(); + if(ticks != null){ + if(this.opt.hMinorLines){ + arr.forEach(ticks.minor, function(tick){ + var y = dim.height - offsets.b - vt(tick.value); + var hMinorLine = this.createLine(s, { + x1: offsets.l, + y1: y, + x2: dim.width - offsets.r, + y2: y + }).setStroke(ta.minorTick); + if(this.animate){ + this._animateGrid(hMinorLine, "h", offsets.l, offsets.r + offsets.l - dim.width); + } + }, this); + } + if(this.opt.hMajorLines){ + arr.forEach(ticks.major, function(tick){ + var y = dim.height - offsets.b - vt(tick.value); + var hMajorLine = this.createLine(s, { + x1: offsets.l, + y1: y, + x2: dim.width - offsets.r, + y2: y + }).setStroke(ta.majorTick); + if(this.animate){ + this._animateGrid(hMajorLine, "h", offsets.l, offsets.r + offsets.l - dim.width); + } + }, this); + } + } + }catch(e){ + // squelch + } + // draw vertical stripes and lines + try{ + var hScaler = this._hAxis.getScaler(), + ht = hScaler.scaler.getTransformerFromModel(hScaler), + ticks = this._hAxis.getTicks(); + if(this != null){ + if(ticks && this.opt.vMinorLines){ + arr.forEach(ticks.minor, function(tick){ + var x = offsets.l + ht(tick.value); + var vMinorLine = this.createLine(s, { + x1: x, + y1: offsets.t, + x2: x, + y2: dim.height - offsets.b + }).setStroke(ta.minorTick); + if(this.animate){ + this._animateGrid(vMinorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); + } + }, this); + } + if(ticks && this.opt.vMajorLines){ + arr.forEach(ticks.major, function(tick){ + var x = offsets.l + ht(tick.value); + var vMajorLine = this.createLine(s, { + x1: x, + y1: offsets.t, + x2: x, + y2: dim.height - offsets.b + }).setStroke(ta.majorTick); + if(this.animate){ + this._animateGrid(vMajorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); + } + }, this); + } + } + }catch(e){ + // squelch + } + this.dirty = false; + return this; // dojox.charting.plot2d.Grid + }, + _animateGrid: function(shape, type, offset, size){ + var transStart = type == "h" ? [offset, 0] : [0, offset]; + var scaleStart = type == "h" ? [1/size, 1] : [1, 1/size]; + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: transStart, end: [0, 0]}, + {name: "scale", start: scaleStart, end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); + +}, +'dojox/gfx/utils':function(){ +define("dojox/gfx/utils", ["dojo/_base/kernel","dojo/_base/lang","./_base", "dojo/_base/html","dojo/_base/array", "dojo/_base/window", "dojo/_base/json", + "dojo/_base/Deferred", "dojo/_base/sniff", "require","dojo/_base/config"], + function(kernel, lang, g, html, arr, win, jsonLib, Deferred, has, require, config){ + var gu = g.utils = {}; + /*===== g= dojox.gfx; gu = dojox.gfx.utils; =====*/ + + lang.mixin(gu, { + forEach: function( + /*dojox.gfx.Surface|dojox.gfx.Shape*/ object, + /*Function|String|Array*/ f, /*Object?*/ o + ){ + // summary: + // Takes a shape or a surface and applies a function "f" to in the context of "o" + // (or global, if missing). If "shape" was a surface or a group, it applies the same + // function to all children recursively effectively visiting all shapes of the underlying scene graph. + // object : The gfx container to iterate. + // f : The function to apply. + // o : The scope. + o = o || win.global; + f.call(o, object); + if(object instanceof g.Surface || object instanceof g.Group){ + arr.forEach(object.children, function(shape){ + gu.forEach(shape, f, o); + }); + } + }, + + serialize: function( + /* dojox.gfx.Surface|dojox.gfx.Shape */ object + ){ + // summary: + // Takes a shape or a surface and returns a DOM object, which describes underlying shapes. + var t = {}, v, isSurface = object instanceof g.Surface; + if(isSurface || object instanceof g.Group){ + t.children = arr.map(object.children, gu.serialize); + if(isSurface){ + return t.children; // Array + } + }else{ + t.shape = object.getShape(); + } + if(object.getTransform){ + v = object.getTransform(); + if(v){ t.transform = v; } + } + if(object.getStroke){ + v = object.getStroke(); + if(v){ t.stroke = v; } + } + if(object.getFill){ + v = object.getFill(); + if(v){ t.fill = v; } + } + if(object.getFont){ + v = object.getFont(); + if(v){ t.font = v; } + } + return t; // Object + }, + + toJson: function( + /* dojox.gfx.Surface|dojox.gfx.Shape */ object, + /* Boolean? */ prettyPrint + ){ + // summary: + // Works just like serialize() but returns a JSON string. If prettyPrint is true, the string is pretty-printed to make it more human-readable. + return jsonLib.toJson(gu.serialize(object), prettyPrint); // String + }, + + deserialize: function( + /* dojox.gfx.Surface|dojox.gfx.Shape */ parent, + /* dojox.gfx.Shape|Array */ object + ){ + // summary: + // Takes a surface or a shape and populates it with an object produced by serialize(). + if(object instanceof Array){ + return arr.map(object, lang.hitch(null, gu.deserialize, parent)); // Array + } + var shape = ("shape" in object) ? parent.createShape(object.shape) : parent.createGroup(); + if("transform" in object){ + shape.setTransform(object.transform); + } + if("stroke" in object){ + shape.setStroke(object.stroke); + } + if("fill" in object){ + shape.setFill(object.fill); + } + if("font" in object){ + shape.setFont(object.font); + } + if("children" in object){ + arr.forEach(object.children, lang.hitch(null, gu.deserialize, shape)); + } + return shape; // dojox.gfx.Shape + }, + + fromJson: function( + /* dojox.gfx.Surface|dojox.gfx.Shape */ parent, + /* String */ json){ + // summary: + // Works just like deserialize() but takes a JSON representation of the object. + return gu.deserialize(parent, jsonLib.fromJson(json)); // Array || dojox.gfx.Shape + }, + + toSvg: function(/*GFX object*/surface){ + // summary: + // Function to serialize a GFX surface to SVG text. + // description: + // Function to serialize a GFX surface to SVG text. The value of this output + // is that there are numerous serverside parser libraries that can render + // SVG into images in various formats. This provides a way that GFX objects + // can be captured in a known format and sent serverside for serialization + // into an image. + // surface: + // The GFX surface to serialize. + // returns: + // Deferred object that will be called when SVG serialization is complete. + + //Since the init and even surface creation can be async, we need to + //return a deferred that will be called when content has serialized. + var deferred = new Deferred(); + + if(g.renderer === "svg"){ + //If we're already in SVG mode, this is easy and quick. + try{ + var svg = gu._cleanSvg(gu._innerXML(surface.rawNode)); + deferred.callback(svg); + }catch(e){ + deferred.errback(e); + } + }else{ + //Okay, now we have to get creative with hidden iframes and the like to + //serialize SVG. + if (!gu._initSvgSerializerDeferred) { + gu._initSvgSerializer(); + } + var jsonForm = gu.toJson(surface); + var serializer = function(){ + try{ + var sDim = surface.getDimensions(); + var width = sDim.width; + var height = sDim.height; + + //Create an attach point in the iframe for the contents. + var node = gu._gfxSvgProxy.document.createElement("div"); + gu._gfxSvgProxy.document.body.appendChild(node); + //Set the node scaling. + win.withDoc(gu._gfxSvgProxy.document, function() { + html.style(node, "width", width); + html.style(node, "height", height); + }, this); + + //Create temp surface to render object to and render. + var ts = gu._gfxSvgProxy[dojox._scopeName].gfx.createSurface(node, width, height); + + //It's apparently possible that a suface creation is async, so we need to use + //the whenLoaded function. Probably not needed for SVG, but making it common + var draw = function(surface) { + try{ + gu._gfxSvgProxy[dojox._scopeName].gfx.utils.fromJson(surface, jsonForm); + + //Get contents and remove temp surface. + var svg = gu._cleanSvg(node.innerHTML); + surface.clear(); + surface.destroy(); + gu._gfxSvgProxy.document.body.removeChild(node); + deferred.callback(svg); + }catch(e){ + deferred.errback(e); + } + }; + ts.whenLoaded(null,draw); + }catch (ex) { + deferred.errback(ex); + } + }; + //See if we can call it directly or pass it to the deferred to be + //called on initialization. + if(gu._initSvgSerializerDeferred.fired > 0){ + serializer(); + }else{ + gu._initSvgSerializerDeferred.addCallback(serializer); + } + } + return deferred; //dojo.Deferred that will be called when serialization finishes. + }, + + //iFrame document used for handling SVG serialization. + _gfxSvgProxy: null, + + //Serializer loaded. + _initSvgSerializerDeferred: null, + + _svgSerializerInitialized: function() { + // summary: + // Internal function to call when the serializer init completed. + // tags: + // private + gu._initSvgSerializerDeferred.callback(true); + }, + + _initSvgSerializer: function(){ + // summary: + // Internal function to initialize the hidden iframe where SVG rendering + // will occur. + // tags: + // private + if(!gu._initSvgSerializerDeferred){ + gu._initSvgSerializerDeferred = new Deferred(); + var f = win.doc.createElement("iframe"); + html.style(f, { + display: "none", + position: "absolute", + width: "1em", + height: "1em", + top: "-10000px" + }); + var intv; + if(has("ie")){ + f.onreadystatechange = function(){ + if(f.contentWindow.document.readyState == "complete"){ + f.onreadystatechange = function() {}; + intv = setInterval(function() { + if(f.contentWindow[kernel.scopeMap["dojo"][1]._scopeName] && + f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx && + f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils){ + clearInterval(intv); + f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow; + f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._svgSerializerInitialized(); + } + }, 50); + } + }; + }else{ + f.onload = function(){ + f.onload = function() {}; + intv = setInterval(function() { + if(f.contentWindow[kernel.scopeMap["dojo"][1]._scopeName] && + f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx && + f.contentWindow[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils){ + clearInterval(intv); + f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._gfxSvgProxy = f.contentWindow; + f.contentWindow.parent[kernel.scopeMap["dojox"][1]._scopeName].gfx.utils._svgSerializerInitialized(); + } + }, 50); + }; + } + //We have to load the GFX SVG proxy frame. Default is to use the one packaged in dojox. + var uri = (config["dojoxGfxSvgProxyFrameUrl"]||require.toUrl("dojox/gfx/resources/gfxSvgProxyFrame.html")); + f.setAttribute("src", uri.toString()); + win.body().appendChild(f); + } + }, + + _innerXML: function(/*Node*/node){ + // summary: + // Implementation of MS's innerXML function, borrowed from dojox.xml.parser. + // node: + // The node from which to generate the XML text representation. + // tags: + // private + if(node.innerXML){ + return node.innerXML; //String + }else if(node.xml){ + return node.xml; //String + }else if(typeof XMLSerializer != "undefined"){ + return (new XMLSerializer()).serializeToString(node); //String + } + return null; + }, + + _cleanSvg: function(svg) { + // summary: + // Internal function that cleans up artifacts in extracted SVG content. + // tags: + // private + if(svg){ + //Make sure the namespace is set. + if(svg.indexOf("xmlns=\"http://www.w3.org/2000/svg\"") == -1){ + svg = svg.substring(4, svg.length); + svg = "<svg xmlns=\"http://www.w3.org/2000/svg\"" + svg; + } + //Same for xmlns:xlink (missing in Chrome and Safari) + if(svg.indexOf("xmlns:xlink=\"http://www.w3.org/1999/xlink\"") == -1){ + svg = svg.substring(4, svg.length); + svg = "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\"" + svg; + } + //and add namespace to href attribute if not done yet + //(FF 5+ adds xlink:href but not the xmlns def) + if(svg.indexOf("xlink:href") === -1){ + svg = svg.replace(/href\s*=/g, "xlink:href="); + } + //Do some other cleanup, like stripping out the + //dojoGfx attributes and quoting ids. + svg = svg.replace(/\bdojoGfx\w*\s*=\s*(['"])\w*\1/g, ""); + svg = svg.replace(/\b__gfxObject__\s*=\s*(['"])\w*\1/g, ""); + svg = svg.replace(/[=]([^"']+?)(\s|>)/g,'="$1"$2'); + } + return svg; //Cleaned SVG text. + } + }); + + return gu; +}); + +}, +'dojox/lang/functional/fold':function(){ +define("dojox/lang/functional/fold", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/window", "./lambda"], + function(lang, arr, win, df){ + +// This module adds high-level functions and related constructs: +// - "fold" family of functions + +// Notes: +// - missing high-level functions are provided with the compatible API: +// foldl, foldl1, foldr, foldr1 +// - missing JS standard functions are provided with the compatible API: +// reduce, reduceRight +// - the fold's counterpart: unfold + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument +// - take an iterator objects as the array argument (only foldl, foldl1, and reduce) + + var empty = {}; + +/*===== + var df = dojox.lang.functional; + =====*/ + lang.mixin(df, { + // classic reduce-class functions + foldl: function(/*Array|String|Object*/ a, /*Function*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right using a seed value as a starting point; returns the final + // value. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var i, n; + if(lang.isArray(a)){ + // array + for(i = 0, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i); + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + for(i = 0; a.hasNext(); z = f.call(o, z, a.next(), i++, a)); + }else{ + // object/dictionary + for(i in a){ + if(!(i in empty)){ + z = f.call(o, z, a[i], i, a); + } + } + } + return z; // Object + }, + foldl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from left + // to right; returns the final value. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var z, i, n; + if(lang.isArray(a)){ + // array + z = a[0]; + for(i = 1, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i); + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + if(a.hasNext()){ + z = a.next(); + for(i = 1; a.hasNext(); z = f.call(o, z, a.next(), i++, a)); + } + }else{ + // object/dictionary + var first = true; + for(i in a){ + if(!(i in empty)){ + if(first){ + z = a[i]; + first = false; + }else{ + z = f.call(o, z, a[i], i, a); + } + } + } + } + return z; // Object + }, + foldr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left using a seed value as a starting point; returns the final + // value. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + for(var i = a.length; i > 0; --i, z = f.call(o, z, a[i], i, a)); + return z; // Object + }, + foldr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: repeatedly applies a binary function to an array from right + // to left; returns the final value. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var n = a.length, z = a[n - 1], i = n - 1; + for(; i > 0; --i, z = f.call(o, z, a[i], i, a)); + return z; // Object + }, + // JS 1.8 standard array functions, which can take a lambda as a parameter. + reduce: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ z){ + // summary: apply a function simultaneously against two values of the array + // (from left-to-right) as to reduce it to a single value. + return arguments.length < 3 ? df.foldl1(a, f) : df.foldl(a, f, z); // Object + }, + reduceRight: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ z){ + // summary: apply a function simultaneously against two values of the array + // (from right-to-left) as to reduce it to a single value. + return arguments.length < 3 ? df.foldr1(a, f) : df.foldr(a, f, z); // Object + }, + // the fold's counterpart: unfold + unfold: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f, + /*Function|String|Array*/ g, /*Object*/ z, /*Object?*/ o){ + // summary: builds an array by unfolding a value + o = o || win.global; f = df.lambda(f); g = df.lambda(g); pr = df.lambda(pr); + var t = []; + for(; !pr.call(o, z); t.push(f.call(o, z)), z = g.call(o, z)); + return t; // Array + } + }); +}); + +}, +'url:dijit/templates/Tooltip.html':"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n></div>\n", +'dojox/charting/plot2d/Spider':function(){ +define("dojox/charting/plot2d/Spider", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/html", "dojo/_base/array", + "dojo/dom-geometry", "dojo/_base/fx", "dojo/fx", "dojo/_base/sniff", + "../Element", "./_PlotEvents", "dojo/_base/Color", "dojox/color/_base", "./common", "../axis2d/common", + "../scaler/primitive", "dojox/gfx", "dojox/gfx/matrix", "dojox/gfx/fx", "dojox/lang/functional", + "dojox/lang/utils", "dojo/fx/easing"], + function(lang, declare, hub, html, arr, domGeom, baseFx, coreFx, has, + Element, PlotEvents, Color, dxcolor, dc, da, primitive, + g, m, gfxfx, df, du, easing){ +/*===== +var Element = dojox.charting.Element; +var PlotEvents = dojox.charting.plot2d._PlotEvents; +=====*/ + var FUDGE_FACTOR = 0.2; // use to overlap fans + + var Spider = declare("dojox.charting.plot2d.Spider", [Element, PlotEvents], { + // summary: + // The plot that represents a typical Spider chart. + defaultParams: { + labels: true, + ticks: false, + fixed: true, + precision: 1, + labelOffset: -10, + labelStyle: "default", // default/rows/auto + htmlLabels: true, // use HTML to draw labels + startAngle: -90, // start angle for slices in degrees + divisions: 3, // radius tick count + axisColor: "", // spider axis color + axisWidth: 0, // spider axis stroke width + spiderColor: "", // spider web color + spiderWidth: 0, // spider web stroke width + seriesWidth: 0, // plot border with + seriesFillAlpha: 0.2, // plot fill alpha + spiderOrigin: 0.16, + markerSize: 3, // radius of plot vertex (px) + spiderType: "polygon", //"circle" + animationType: easing.backOut, + axisTickFont: "", + axisTickFontColor: "", + axisFont: "", + axisFontColor: "" + }, + optionalParams: { + radius: 0, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Create a Spider plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.dyn = []; + this.datas = {}; + this.labelKey = []; + this.oldSeriePoints = {}; + this.animations = {}; + }, + clear: function(){ + // summary: + // Clear out all of the information tied to this plot. + // returns: dojox.charting.plot2d.Spider + // A reference to this plot for functional chaining. + this.dirty = true; + this.dyn = []; + this.series = []; + this.datas = {}; + this.labelKey = []; + this.oldSeriePoints = {}; + this.animations = {}; + return this; // dojox.charting.plot2d.Spider + }, + setAxis: function(axis){ + // summary: + // Dummy method, since axes are irrelevant with a Spider chart. + // returns: dojox.charting.plot2d.Spider + // The reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Spider + }, + addSeries: function(run){ + // summary: + // Add a data series to this plot. + // run: dojox.charting.Series + // The series to be added. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + var matched = false; + this.series.push(run); + for(var key in run.data){ + var val = run.data[key], + data = this.datas[key]; + if(data){ + data.vlist.push(val); + data.min = Math.min(data.min, val); + data.max = Math.max(data.max, val); + }else{ + this.datas[key] = {min: val, max: val, vlist: [val]}; + } + } + if (this.labelKey.length <= 0) { + for (var key in run.data) { + this.labelKey.push(key); + } + } + return this; // dojox.charting.plot2d.Base + }, + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return dc.collectSimpleStats(this.series); + }, + calculateAxes: function(dim){ + // summary: + // Stub function for running the axis calculations (depricated). + // dim: Object + // An object of the form { width, height } + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.initializeScalers(dim, this.getSeriesStats()); + return this; // dojox.charting.plot2d.Base + }, + getRequiredColors: function(){ + // summary: + // Get how many data series we have, so we know how many colors to use. + // returns: Number + // The number of colors needed. + return this.series.length; // Number + }, + initializeScalers: function(dim, stats){ + // summary: + // Initializes scalers using attached axes. + // dim: Object: + // Size of a plot area in pixels as {width, height}. + // stats: Object: + // Min/max of data in both directions as {hmin, hmax, vmin, vmax}. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + if(this._hAxis){ + if(!this._hAxis.initialized()){ + this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); + } + this._hScaler = this._hAxis.getScaler(); + }else{ + this._hScaler = primitive.buildScaler(stats.hmin, stats.hmax, dim.width); + } + if(this._vAxis){ + if(!this._vAxis.initialized()){ + this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); + } + this._vScaler = this._vAxis.getScaler(); + }else{ + this._vScaler = primitive.buildScaler(stats.vmin, stats.vmax, dim.height); + } + return this; // dojox.charting.plot2d.Base + }, + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Spider + // A reference to this plot for functional chaining. + if(!this.dirty){ return this; } + this.dirty = false; + this.cleanGroup(); + var s = this.group, t = this.chart.theme; + this.resetEvents(); + + if(!this.series || !this.series.length){ + return this; + } + + // calculate the geometry + var o = this.opt, ta = t.axis, + rx = (dim.width - offsets.l - offsets.r) / 2, + ry = (dim.height - offsets.t - offsets.b) / 2, + r = Math.min(rx, ry), + axisTickFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font) || "normal normal normal 7pt Tahoma", + axisFont = o.axisFont || (ta.tick && ta.tick.titleFont) || "normal normal normal 11pt Tahoma", + axisTickFontColor = o.axisTickFontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "silver", + axisFontColor = o.axisFontColor || (ta.tick && ta.tick.titleFontColor) || "black", + axisColor = o.axisColor || (ta.tick && ta.tick.axisColor) || "silver", + spiderColor = o.spiderColor || (ta.tick && ta.tick.spiderColor) || "silver", + axisWidth = o.axisWidth || (ta.stroke && ta.stroke.width) || 2, + spiderWidth = o.spiderWidth || (ta.stroke && ta.stroke.width) || 2, + seriesWidth = o.seriesWidth || (ta.stroke && ta.stroke.width) || 2, + asize = g.normalizedLength(g.splitFontString(axisFont).size), + startAngle = m._degToRad(o.startAngle), + start = startAngle, step, filteredRun, slices, labels, shift, labelR, + outerPoints, innerPoints, divisionPoints, divisionRadius, labelPoints, + ro = o.spiderOrigin, dv = o.divisions >= 3 ? o.divisions : 3, ms = o.markerSize, + spt = o.spiderType, at = o.animationType, lboffset = o.labelOffset < -10 ? o.labelOffset : -10, + axisExtra = 0.2; + + if(o.labels){ + labels = arr.map(this.series, function(s){ + return s.name; + }, this); + shift = df.foldl1(df.map(labels, function(label, i){ + var font = t.series.font; + return g._base._getTextBox(label, { + font: font + }).w; + }, this), "Math.max(a, b)") / 2; + r = Math.min(rx - 2 * shift, ry - asize) + lboffset; + labelR = r - lboffset; + } + if ("radius" in o) { + r = o.radius; + labelR = r - lboffset; + } + r /= (1+axisExtra); + var circle = { + cx: offsets.l + rx, + cy: offsets.t + ry, + r: r + }; + + for (var i = this.series.length - 1; i >= 0; i--) { + var serieEntry = this.series[i]; + if (!this.dirty && !serieEntry.dirty) { + t.skip(); + continue; + } + serieEntry.cleanGroup(); + var run = serieEntry.data; + if (run !== null) { + var len = this._getObjectLength(run); + //construct connect points + if (!outerPoints || outerPoints.length <= 0) { + outerPoints = [], innerPoints = [], labelPoints = []; + this._buildPoints(outerPoints, len, circle, r, start, true); + this._buildPoints(innerPoints, len, circle, r*ro, start, true); + this._buildPoints(labelPoints, len, circle, labelR, start); + if(dv > 2){ + divisionPoints = [], divisionRadius = []; + for (var j = 0; j < dv - 2; j++) { + divisionPoints[j] = []; + this._buildPoints(divisionPoints[j], len, circle, r*(ro + (1-ro)*(j+1)/(dv-1)), start, true); + divisionRadius[j] = r*(ro + (1-ro)*(j+1)/(dv-1)); + } + } + } + } + } + + //draw Spider + //axis + var axisGroup = s.createGroup(), axisStroke = {color: axisColor, width: axisWidth}, + spiderStroke = {color: spiderColor, width: spiderWidth}; + for (var j = outerPoints.length - 1; j >= 0; --j) { + var point = outerPoints[j], + st = { + x: point.x + (point.x - circle.cx) * axisExtra, + y: point.y + (point.y - circle.cy) * axisExtra + }, + nd = { + x: point.x + (point.x - circle.cx) * axisExtra / 2, + y: point.y + (point.y - circle.cy) * axisExtra / 2 + }; + axisGroup.createLine({ + x1: circle.cx, + y1: circle.cy, + x2: st.x, + y2: st.y + }).setStroke(axisStroke); + //arrow + this._drawArrow(axisGroup, st, nd, axisStroke); + } + + // draw the label + var labelGroup = s.createGroup(); + for (var j = labelPoints.length - 1; j >= 0; --j) { + var point = labelPoints[j], + fontWidth = g._base._getTextBox(this.labelKey[j], {font: axisFont}).w || 0, + render = this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx", + elem = da.createText[render](this.chart, labelGroup, (!domGeom.isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y, + "middle", this.labelKey[j], axisFont, axisFontColor); + if (this.opt.htmlLabels) { + this.htmlElements.push(elem); + } + } + + //spider web: polygon or circle + var spiderGroup = s.createGroup(); + if(spt == "polygon"){ + spiderGroup.createPolyline(outerPoints).setStroke(spiderStroke); + spiderGroup.createPolyline(innerPoints).setStroke(spiderStroke); + if (divisionPoints.length > 0) { + for (var j = divisionPoints.length - 1; j >= 0; --j) { + spiderGroup.createPolyline(divisionPoints[j]).setStroke(spiderStroke); + } + } + }else{//circle + var ccount = this._getObjectLength(this.datas); + spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r}).setStroke(spiderStroke); + spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r*ro}).setStroke(spiderStroke); + if (divisionRadius.length > 0) { + for (var j = divisionRadius.length - 1; j >= 0; --j) { + spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: divisionRadius[j]}).setStroke(spiderStroke); + } + } + } + //text + var textGroup = s.createGroup(), len = this._getObjectLength(this.datas), k = 0; + for(var key in this.datas){ + var data = this.datas[key], min = data.min, max = data.max, distance = max - min, + end = start + 2 * Math.PI * k / len; + for (var i = 0; i < dv; i++) { + var text = min + distance*i/(dv-1), point = this._getCoordinate(circle, r*(ro + (1-ro)*i/(dv-1)), end); + text = this._getLabel(text); + var fontWidth = g._base._getTextBox(text, {font: axisTickFont}).w || 0, + render = this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"; + if (this.opt.htmlLabels) { + this.htmlElements.push(da.createText[render] + (this.chart, textGroup, (!domGeom.isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y, + "start", text, axisTickFont, axisTickFontColor)); + } + } + k++; + } + + //draw series (animation) + this.chart.seriesShapes = {}; + var animationConnections = []; + for (var i = this.series.length - 1; i >= 0; i--) { + var serieEntry = this.series[i], run = serieEntry.data; + if (run !== null) { + //series polygon + var seriePoints = [], k = 0, tipData = []; + for(var key in run){ + var data = this.datas[key], min = data.min, max = data.max, distance = max - min, + entry = run[key], end = start + 2 * Math.PI * k / len, + point = this._getCoordinate(circle, r*(ro + (1-ro)*(entry-min)/distance), end); + seriePoints.push(point); + tipData.push({sname: serieEntry.name, key: key, data: entry}); + k++; + } + seriePoints[seriePoints.length] = seriePoints[0]; + tipData[tipData.length] = tipData[0]; + var polygonBoundRect = this._getBoundary(seriePoints), + theme = t.next("spider", [o, serieEntry]), ts = serieEntry.group, + f = g.normalizeColor(theme.series.fill), sk = {color: theme.series.fill, width: seriesWidth}; + f.a = o.seriesFillAlpha; + serieEntry.dyn = {fill: f, stroke: sk}; + + var osps = this.oldSeriePoints[serieEntry.name]; + var cs = this._createSeriesEntry(ts, (osps || innerPoints), seriePoints, f, sk, r, ro, ms, at); + this.chart.seriesShapes[serieEntry.name] = cs; + this.oldSeriePoints[serieEntry.name] = seriePoints; + + var po = { + element: "spider_poly", + index: i, + id: "spider_poly_"+serieEntry.name, + run: serieEntry, + plot: this, + shape: cs.poly, + parent: ts, + brect: polygonBoundRect, + cx: circle.cx, + cy: circle.cy, + cr: r, + f: f, + s: s + }; + this._connectEvents(po); + + var so = { + element: "spider_plot", + index: i, + id: "spider_plot_"+serieEntry.name, + run: serieEntry, + plot: this, + shape: serieEntry.group + }; + this._connectEvents(so); + + arr.forEach(cs.circles, function(c, i){ + var shape = c.getShape(), + co = { + element: "spider_circle", + index: i, + id: "spider_circle_"+serieEntry.name+i, + run: serieEntry, + plot: this, + shape: c, + parent: ts, + tdata: tipData[i], + cx: seriePoints[i].x, + cy: seriePoints[i].y, + f: f, + s: s + }; + this._connectEvents(co); + }, this); + } + } + return this; // dojox.charting.plot2d.Spider + }, + _createSeriesEntry: function(ts, osps, sps, f, sk, r, ro, ms, at){ + //polygon + var spoly = ts.createPolyline(osps).setFill(f).setStroke(sk), scircle = []; + for (var j = 0; j < osps.length; j++) { + var point = osps[j], cr = ms; + var circle = ts.createCircle({cx: point.x, cy: point.y, r: cr}).setFill(f).setStroke(sk); + scircle.push(circle); + } + + var anims = arr.map(sps, function(np, j){ + // create animation + var sp = osps[j], + anim = new baseFx.Animation({ + duration: 1000, + easing: at, + curve: [sp.y, np.y] + }); + var spl = spoly, sc = scircle[j]; + hub.connect(anim, "onAnimate", function(y){ + //apply poly + var pshape = spl.getShape(); + pshape.points[j].y = y; + spl.setShape(pshape); + //apply circle + var cshape = sc.getShape(); + cshape.cy = y; + sc.setShape(cshape); + }); + return anim; + }); + + var anims1 = arr.map(sps, function(np, j){ + // create animation + var sp = osps[j], + anim = new baseFx.Animation({ + duration: 1000, + easing: at, + curve: [sp.x, np.x] + }); + var spl = spoly, sc = scircle[j]; + hub.connect(anim, "onAnimate", function(x){ + //apply poly + var pshape = spl.getShape(); + pshape.points[j].x = x; + spl.setShape(pshape); + //apply circle + var cshape = sc.getShape(); + cshape.cx = x; + sc.setShape(cshape); + }); + return anim; + }); + var masterAnimation = coreFx.combine(anims.concat(anims1)); //dojo.fx.chain(anims); + masterAnimation.play(); + return {group :ts, poly: spoly, circles: scircle}; + }, + plotEvent: function(o){ + // summary: + // Stub function for use by specific plots. + // o: Object + // An object intended to represent event parameters. + var runName = o.id ? o.id : "default", a; + if (runName in this.animations) { + a = this.animations[runName]; + a.anim && a.anim.stop(true); + } else { + a = this.animations[runName] = {}; + } + if(o.element == "spider_poly"){ + if(!a.color){ + var color = o.shape.getFill(); + if(!color || !(color instanceof Color)){ + return; + } + a.color = { + start: color, + end: transColor(color) + }; + } + var start = a.color.start, end = a.color.end; + if(o.type == "onmouseout"){ + // swap colors + var t = start; start = end; end = t; + } + a.anim = gfxfx.animateFill({ + shape: o.shape, + duration: 800, + easing: easing.backOut, + color: {start: start, end: end} + }); + a.anim.play(); + }else if(o.element == "spider_circle"){ + var init, scale, defaultScale = 1.5; + if(o.type == "onmouseover"){ + init = m.identity; + scale = defaultScale; + //show tooltip + var aroundRect = {type: "rect"}; + aroundRect.x = o.cx; + aroundRect.y = o.cy; + aroundRect.width = aroundRect.height = 1; + var lt = html.coords(this.chart.node, true); + aroundRect.x += lt.x; + aroundRect.y += lt.y; + aroundRect.x = Math.round(aroundRect.x); + aroundRect.y = Math.round(aroundRect.y); + aroundRect.width = Math.ceil(aroundRect.width); + aroundRect.height = Math.ceil(aroundRect.height); + this.aroundRect = aroundRect; + var position = ["after", "before"]; + dc.doIfLoaded("dijit/Tooltip", dojo.hitch(this, function(Tooltip){ + Tooltip.show(o.tdata.sname + "<br/>" + o.tdata.key + "<br/>" + o.tdata.data, this.aroundRect, position); + })); + }else{ + init = m.scaleAt(defaultScale, o.cx, o.cy); + scale = 1/defaultScale; + dc.doIfLoaded("dijit/Tooltip", dojo.hitch(this, function(Tooltip){ + this.aroundRect && Tooltip.hide(this.aroundRect); + })); + } + var cs = o.shape.getShape(), + init = m.scaleAt(defaultScale, cs.cx, cs.cy), + kwArgs = { + shape: o.shape, + duration: 200, + easing: easing.backOut, + transform: [ + {name: "scaleAt", start: [1, cs.cx, cs.cy], end: [scale, cs.cx, cs.cy]}, + init + ] + }; + a.anim = gfxfx.animateTransform(kwArgs); + a.anim.play(); + }else if(o.element == "spider_plot"){ + //dojo gfx function "moveToFront" not work in IE + if (o.type == "onmouseover" && !has("ie")) { + o.shape.moveToFront(); + } + } + }, + _getBoundary: function(points){ + var xmax = points[0].x, + xmin = points[0].x, + ymax = points[0].y, + ymin = points[0].y; + for(var i = 0; i < points.length; i++){ + var point = points[i]; + xmax = Math.max(point.x, xmax); + ymax = Math.max(point.y, ymax); + xmin = Math.min(point.x, xmin); + ymin = Math.min(point.y, ymin); + } + return { + x: xmin, + y: ymin, + width: xmax - xmin, + height: ymax - ymin + }; + }, + + _drawArrow: function(s, start, end, stroke){ + var len = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)), + sin = (end.y - start.y)/len, cos = (end.x - start.x)/len, + point2 = {x: end.x + (len/3)*(-sin), y: end.y + (len/3)*cos}, + point3 = {x: end.x + (len/3)*sin, y: end.y + (len/3)*(-cos)}; + s.createPolyline([start, point2, point3]).setFill(stroke.color).setStroke(stroke); + }, + + _buildPoints: function(points, count, circle, radius, angle, recursive){ + for (var i = 0; i < count; i++) { + var end = angle + 2 * Math.PI * i / count; + points.push(this._getCoordinate(circle, radius, end)); + } + if(recursive){ + points.push(this._getCoordinate(circle, radius, angle + 2 * Math.PI)); + } + }, + + _getCoordinate: function(circle, radius, angle){ + return { + x: circle.cx + radius * Math.cos(angle), + y: circle.cy + radius * Math.sin(angle) + } + }, + + _getObjectLength: function(obj){ + var count = 0; + if(lang.isObject(obj)){ + for(var key in obj){ + count++; + } + } + return count; + }, + + // utilities + _getLabel: function(number){ + return dc.getLabel(number, this.opt.fixed, this.opt.precision); + } + }); + + function transColor(color){ + var a = new dxcolor.Color(color), + x = a.toHsl(); + if(x.s == 0){ + x.l = x.l < 50 ? 100 : 0; + }else{ + x.s = 100; + if(x.l < 50){ + x.l = 75; + }else if(x.l > 75){ + x.l = 50; + }else{ + x.l = x.l - 50 > 75 - x.l ? + 50 : 75; + } + } + var color = dxcolor.fromHsl(x); + color.a = 0.7; + return color; + } + + return Spider; // dojox.plot2d.Spider +}); + +}, +'dojox/charting/plot2d/StackedBars':function(){ +define("dojox/charting/plot2d/StackedBars", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Bars", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/functional/sequence"], + function(lang, arr, declare, Bars, dc, df, dfr, dfs){ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); +/*===== +var bars = dojox.charting.plot2d.Bars; +=====*/ + return declare("dojox.charting.plot2d.StackedBars", Bars, { + // summary: + // The plot object representing a stacked bar chart (horizontal bars). + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectStackedStats(this.series), t; + this._maxRunLength = stats.hmax; + stats.hmin -= 0.5; + stats.hmax += 0.5; + t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; + t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; + return stats; + }, + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.StackedBars + // A reference to this plot for functional chaining. + if(this._maxRunLength <= 0){ + return this; + } + + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + } + // draw runs in backwards + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, height, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + events = this.events(); + f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt); + gap = f.gap; + height = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("bar", [this.opt, run]), s = run.group, + eventSeries = new Array(acc.length); + for(var j = 0; j < acc.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = acc[j], + width = ht(v), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "bar", value, true) : + t.post(theme, "bar"); + if(width >= 0 && height >= 1){ + var rect = { + x: offsets.l, + y: dim.height - offsets.b - vt(j + 1.5) + gap, + width: width, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "bar", + index: j, + run: run, + shape: shape, + x: v, + y: j + 1.5 + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateBar(shape, offsets.l, -width); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + } + this.dirty = false; + return this; // dojox.charting.plot2d.StackedBars + } + }); +}); + +}, +'dojox/charting/themes/GreySkies':function(){ +define("dojox/charting/themes/GreySkies", ["../Theme", "./common"], function(Theme, themes){ + + themes.GreySkies=new Theme(Theme._def); + + return themes.GreySkies; +}); + +}, +'dojox/charting/plot2d/Columns':function(){ +define("dojox/charting/plot2d/Columns", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, arr, declare, Base, dc, df, dfr, du, fx){ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); +/*===== +var Base = dojox.charting.plot2d.Base; +=====*/ + + return declare("dojox.charting.plot2d.Columns", Base, { + // summary: + // The plot object representing a column chart (vertical bars). + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 0, // gap between columns in pixels + animate: null, // animate bars into place + enableCache: false + }, + optionalParams: { + minBarSize: 1, // minimal column width in pixels + maxBarSize: 1, // maximal column width in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a columns chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectSimpleStats(this.series); + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + + createRect: function(run, creator, params){ + var rect; + if(this.opt.enableCache && run._rectFreePool.length > 0){ + rect = run._rectFreePool.pop(); + rect.setShape(params); + // was cleared, add it back + creator.add(rect); + }else{ + rect = creator.createRect(params); + } + if(this.opt.enableCache){ + run._rectUsePool.push(rect); + } + return rect; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Columns + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + var t = this.getSeriesStats(); + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._vScaler.bounds.lower), + baselineHeight = vt(baseline), + min = Math.max(0, Math.floor(this._hScaler.bounds.from - 1)), max = Math.ceil(this._hScaler.bounds.to), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(this.opt.enableCache){ + run._rectFreePool = (run._rectFreePool?run._rectFreePool:[]).concat(run._rectUsePool?run._rectUsePool:[]); + run._rectUsePool = []; + } + var theme = t.next("column", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + var l = Math.min(run.data.length, max); + for(var j = min; j < l; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + vv = vt(v), + height = vv - baselineHeight, + h = Math.abs(height), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "column", value, true) : + t.post(theme, "column"); + if(width >= 1 && h >= 0){ + var rect = { + x: offsets.l + ht(j + 0.5) + gap, + y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight), + width: width, height: h + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = this.createRect(run, s, rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "column", + index: j, + run: run, + shape: shape, + x: j + 0.5, + y: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Columns + }, + _animateColumn: function(shape, voffset, vsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]}, + {name: "scale", start: [1, 1/vsize], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); + +}, +'dijit/place':function(){ +define("dijit/place", [ + "dojo/_base/array", // array.forEach array.map array.some + "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position + "dojo/dom-style", // domStyle.getComputedStyle + "dojo/_base/kernel", // kernel.deprecated + "dojo/_base/window", // win.body + "dojo/window", // winUtils.getBox + "." // dijit (defining dijit.place to match API doc) +], function(array, domGeometry, domStyle, kernel, win, winUtils, dijit){ + + // module: + // dijit/place + // summary: + // Code to place a popup relative to another node + + + function _place(/*DomNode*/ node, choices, layoutNode, aroundNodeCoords){ + // summary: + // Given a list of spots to put node, put it at the first spot where it fits, + // of if it doesn't fit anywhere then the place with the least overflow + // choices: Array + // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} } + // Above example says to put the top-left corner of the node at (10,20) + // layoutNode: Function(node, aroundNodeCorner, nodeCorner, size) + // for things like tooltip, they are displayed differently (and have different dimensions) + // based on their orientation relative to the parent. This adjusts the popup based on orientation. + // It also passes in the available size for the popup, which is useful for tooltips to + // tell them that their width is limited to a certain amount. layoutNode() may return a value expressing + // how much the popup had to be modified to fit into the available space. This is used to determine + // what the best placement is. + // aroundNodeCoords: Object + // Size of aroundNode, ex: {w: 200, h: 50} + + // get {x: 10, y: 10, w: 100, h:100} type obj representing position of + // viewport over document + var view = winUtils.getBox(); + + // This won't work if the node is inside a <div style="position: relative">, + // so reattach it to win.doc.body. (Otherwise, the positioning will be wrong + // and also it might get cutoff) + if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ + win.body().appendChild(node); + } + + var best = null; + array.some(choices, function(choice){ + var corner = choice.corner; + var pos = choice.pos; + var overflow = 0; + + // calculate amount of space available given specified position of node + var spaceAvailable = { + w: { + 'L': view.l + view.w - pos.x, + 'R': pos.x - view.l, + 'M': view.w + }[corner.charAt(1)], + h: { + 'T': view.t + view.h - pos.y, + 'B': pos.y - view.t, + 'M': view.h + }[corner.charAt(0)] + }; + + // configure node to be displayed in given position relative to button + // (need to do this in order to get an accurate size for the node, because + // a tooltip's size changes based on position, due to triangle) + if(layoutNode){ + var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords); + overflow = typeof res == "undefined" ? 0 : res; + } + + // get node's size + var style = node.style; + var oldDisplay = style.display; + var oldVis = style.visibility; + if(style.display == "none"){ + style.visibility = "hidden"; + style.display = ""; + } + var mb = domGeometry. getMarginBox(node); + style.display = oldDisplay; + style.visibility = oldVis; + + // coordinates and size of node with specified corner placed at pos, + // and clipped by viewport + var + startXpos = { + 'L': pos.x, + 'R': pos.x - mb.w, + 'M': Math.max(view.l, Math.min(view.l + view.w, pos.x + (mb.w >> 1)) - mb.w) // M orientation is more flexible + }[corner.charAt(1)], + startYpos = { + 'T': pos.y, + 'B': pos.y - mb.h, + 'M': Math.max(view.t, Math.min(view.t + view.h, pos.y + (mb.h >> 1)) - mb.h) + }[corner.charAt(0)], + startX = Math.max(view.l, startXpos), + startY = Math.max(view.t, startYpos), + endX = Math.min(view.l + view.w, startXpos + mb.w), + endY = Math.min(view.t + view.h, startYpos + mb.h), + width = endX - startX, + height = endY - startY; + + overflow += (mb.w - width) + (mb.h - height); + + if(best == null || overflow < best.overflow){ + best = { + corner: corner, + aroundCorner: choice.aroundCorner, + x: startX, + y: startY, + w: width, + h: height, + overflow: overflow, + spaceAvailable: spaceAvailable + }; + } + + return !overflow; + }); + + // In case the best position is not the last one we checked, need to call + // layoutNode() again. + if(best.overflow && layoutNode){ + layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords); + } + + // And then position the node. Do this last, after the layoutNode() above + // has sized the node, due to browser quirks when the viewport is scrolled + // (specifically that a Tooltip will shrink to fit as though the window was + // scrolled to the left). + // + // In RTL mode, set style.right rather than style.left so in the common case, + // window resizes move the popup along with the aroundNode. + var l = domGeometry.isBodyLtr(), + s = node.style; + s.top = best.y + "px"; + s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px"; + s[l ? "right" : "left"] = "auto"; // needed for FF or else tooltip goes to far left + + return best; + } + + /*===== + dijit.place.__Position = function(){ + // x: Integer + // horizontal coordinate in pixels, relative to document body + // y: Integer + // vertical coordinate in pixels, relative to document body + + this.x = x; + this.y = y; + }; + =====*/ + + /*===== + dijit.place.__Rectangle = function(){ + // x: Integer + // horizontal offset in pixels, relative to document body + // y: Integer + // vertical offset in pixels, relative to document body + // w: Integer + // width in pixels. Can also be specified as "width" for backwards-compatibility. + // h: Integer + // height in pixels. Can also be specified as "height" from backwards-compatibility. + + this.x = x; + this.y = y; + this.w = w; + this.h = h; + }; + =====*/ + + return (dijit.place = { + // summary: + // Code to place a DOMNode relative to another DOMNode. + // Load using require(["dijit/place"], function(place){ ... }). + + at: function(node, pos, corners, padding){ + // summary: + // Positions one of the node's corners at specified position + // such that node is fully visible in viewport. + // description: + // NOTE: node is assumed to be absolutely or relatively positioned. + // node: DOMNode + // The node to position + // pos: dijit.place.__Position + // Object like {x: 10, y: 20} + // corners: String[] + // Array of Strings representing order to try corners in, like ["TR", "BL"]. + // Possible values are: + // * "BL" - bottom left + // * "BR" - bottom right + // * "TL" - top left + // * "TR" - top right + // padding: dijit.place.__Position? + // optional param to set padding, to put some buffer around the element you want to position. + // example: + // Try to place node's top right corner at (10,20). + // If that makes node go (partially) off screen, then try placing + // bottom left corner at (10,20). + // | place(node, {x: 10, y: 20}, ["TR", "BL"]) + var choices = array.map(corners, function(corner){ + var c = { corner: corner, pos: {x:pos.x,y:pos.y} }; + if(padding){ + c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x; + c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y; + } + return c; + }); + + return _place(node, choices); + }, + + around: function( + /*DomNode*/ node, + /*DomNode || dijit.place.__Rectangle*/ anchor, + /*String[]*/ positions, + /*Boolean*/ leftToRight, + /*Function?*/ layoutNode){ + + // summary: + // Position node adjacent or kitty-corner to anchor + // such that it's fully visible in viewport. + // + // description: + // Place node such that corner of node touches a corner of + // aroundNode, and that node is fully visible. + // + // anchor: + // Either a DOMNode or a __Rectangle (object with x, y, width, height). + // + // positions: + // Ordered list of positions to try matching up. + // * before: places drop down to the left of the anchor node/widget, or to the right in the case + // of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down + // with the top of the anchor, or the bottom of the drop down with bottom of the anchor. + // * after: places drop down to the right of the anchor node/widget, or to the left in the case + // of RTL scripts like Hebrew and Arabic; aligns either the top of the drop down + // with the top of the anchor, or the bottom of the drop down with bottom of the anchor. + // * before-centered: centers drop down to the left of the anchor node/widget, or to the right + // in the case of RTL scripts like Hebrew and Arabic + // * after-centered: centers drop down to the right of the anchor node/widget, or to the left + // in the case of RTL scripts like Hebrew and Arabic + // * above-centered: drop down is centered above anchor node + // * above: drop down goes above anchor node, left sides aligned + // * above-alt: drop down goes above anchor node, right sides aligned + // * below-centered: drop down is centered above anchor node + // * below: drop down goes below anchor node + // * below-alt: drop down goes below anchor node, right sides aligned + // + // layoutNode: Function(node, aroundNodeCorner, nodeCorner) + // For things like tooltip, they are displayed differently (and have different dimensions) + // based on their orientation relative to the parent. This adjusts the popup based on orientation. + // + // leftToRight: + // True if widget is LTR, false if widget is RTL. Affects the behavior of "above" and "below" + // positions slightly. + // + // example: + // | placeAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'}); + // This will try to position node such that node's top-left corner is at the same position + // as the bottom left corner of the aroundNode (ie, put node below + // aroundNode, with left edges aligned). If that fails it will try to put + // the bottom-right corner of node where the top right corner of aroundNode is + // (ie, put node above aroundNode, with right edges aligned) + // + + // if around is a DOMNode (or DOMNode id), convert to coordinates + var aroundNodePos = (typeof anchor == "string" || "offsetWidth" in anchor) + ? domGeometry.position(anchor, true) + : anchor; + + // Adjust anchor positioning for the case that a parent node has overflw hidden, therefore cuasing the anchor not to be completely visible + if(anchor.parentNode){ + var parent = anchor.parentNode; + while(parent && parent.nodeType == 1 && parent.nodeName != "BODY"){ //ignoring the body will help performance + var parentPos = domGeometry.position(parent, true); + var parentStyleOverflow = domStyle.getComputedStyle(parent).overflow; + if(parentStyleOverflow == "hidden" || parentStyleOverflow == "auto" || parentStyleOverflow == "scroll"){ + var bottomYCoord = Math.min(aroundNodePos.y + aroundNodePos.h, parentPos.y + parentPos.h); + var rightXCoord = Math.min(aroundNodePos.x + aroundNodePos.w, parentPos.x + parentPos.w); + aroundNodePos.x = Math.max(aroundNodePos.x, parentPos.x); + aroundNodePos.y = Math.max(aroundNodePos.y, parentPos.y); + aroundNodePos.h = bottomYCoord - aroundNodePos.y; + aroundNodePos.w = rightXCoord - aroundNodePos.x; + } + parent = parent.parentNode; + } + } + + var x = aroundNodePos.x, + y = aroundNodePos.y, + width = "w" in aroundNodePos ? aroundNodePos.w : (aroundNodePos.w = aroundNodePos.width), + height = "h" in aroundNodePos ? aroundNodePos.h : (kernel.deprecated("place.around: dijit.place.__Rectangle: { x:"+x+", y:"+y+", height:"+aroundNodePos.height+", width:"+width+" } has been deprecated. Please use { x:"+x+", y:"+y+", h:"+aroundNodePos.height+", w:"+width+" }", "", "2.0"), aroundNodePos.h = aroundNodePos.height); + + // Convert positions arguments into choices argument for _place() + var choices = []; + function push(aroundCorner, corner){ + choices.push({ + aroundCorner: aroundCorner, + corner: corner, + pos: { + x: { + 'L': x, + 'R': x + width, + 'M': x + (width >> 1) + }[aroundCorner.charAt(1)], + y: { + 'T': y, + 'B': y + height, + 'M': y + (height >> 1) + }[aroundCorner.charAt(0)] + } + }) + } + array.forEach(positions, function(pos){ + var ltr = leftToRight; + switch(pos){ + case "above-centered": + push("TM", "BM"); + break; + case "below-centered": + push("BM", "TM"); + break; + case "after-centered": + ltr = !ltr; + // fall through + case "before-centered": + push(ltr ? "ML" : "MR", ltr ? "MR" : "ML"); + break; + case "after": + ltr = !ltr; + // fall through + case "before": + push(ltr ? "TL" : "TR", ltr ? "TR" : "TL"); + push(ltr ? "BL" : "BR", ltr ? "BR" : "BL"); + break; + case "below-alt": + ltr = !ltr; + // fall through + case "below": + // first try to align left borders, next try to align right borders (or reverse for RTL mode) + push(ltr ? "BL" : "BR", ltr ? "TL" : "TR"); + push(ltr ? "BR" : "BL", ltr ? "TR" : "TL"); + break; + case "above-alt": + ltr = !ltr; + // fall through + case "above": + // first try to align left borders, next try to align right borders (or reverse for RTL mode) + push(ltr ? "TL" : "TR", ltr ? "BL" : "BR"); + push(ltr ? "TR" : "TL", ltr ? "BR" : "BL"); + break; + default: + // To assist dijit/_base/place, accept arguments of type {aroundCorner: "BL", corner: "TL"}. + // Not meant to be used directly. + push(pos.aroundCorner, pos.corner); + } + }); + + var position = _place(node, choices, layoutNode, {w: width, h: height}); + position.aroundNodePos = aroundNodePos; + + return position; + } + }); +}); + +}, +'dojox/lang/functional/array':function(){ +define("dojox/lang/functional/array", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array", "dojo/_base/window", "./lambda"], + function(dojo, lang, arr, win, df){ + +// This module adds high-level functions and related constructs: +// - array-processing functions similar to standard JS functions + +// Notes: +// - this module provides JS standard methods similar to high-level functions in dojo/_base/array.js: +// forEach, map, filter, every, some + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - operate on dense arrays +// - take a string as the array argument +// - take an iterator objects as the array argument + + var empty = {}; + +/*===== + var df = dojox.lang.functional; + =====*/ + lang.mixin(df, { + // JS 1.6 standard array functions, which can take a lambda as a parameter. + // Consider using dojo._base.array functions, if you don't need the lambda support. + filter: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with all elements that pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var t = [], v, i, n; + if(lang.isArray(a)){ + // array + for(i = 0, n = a.length; i < n; ++i){ + v = a[i]; + if(f.call(o, v, i, a)){ t.push(v); } + } + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + for(i = 0; a.hasNext();){ + v = a.next(); + if(f.call(o, v, i++, a)){ t.push(v); } + } + }else{ + // object/dictionary + for(i in a){ + if(!(i in empty)){ + v = a[i]; + if(f.call(o, v, i, a)){ t.push(v); } + } + } + } + return t; // Array + }, + forEach: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: executes a provided function once per array element. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var i, n; + if(lang.isArray(a)){ + // array + for(i = 0, n = a.length; i < n; f.call(o, a[i], i, a), ++i); + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + for(i = 0; a.hasNext(); f.call(o, a.next(), i++, a)); + }else{ + // object/dictionary + for(i in a){ + if(!(i in empty)){ + f.call(o, a[i], i, a); + } + } + } + return o; // Object + }, + map: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates a new array with the results of calling + // a provided function on every element in this array. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var t, n, i; + if(lang.isArray(a)){ + // array + t = new Array(n = a.length); + for(i = 0; i < n; t[i] = f.call(o, a[i], i, a), ++i); + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + t = []; + for(i = 0; a.hasNext(); t.push(f.call(o, a.next(), i++, a))); + }else{ + // object/dictionary + t = []; + for(i in a){ + if(!(i in empty)){ + t.push(f.call(o, a[i], i, a)); + } + } + } + return t; // Array + }, + every: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether all elements in the array pass the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var i, n; + if(lang.isArray(a)){ + // array + for(i = 0, n = a.length; i < n; ++i){ + if(!f.call(o, a[i], i, a)){ + return false; // Boolean + } + } + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + for(i = 0; a.hasNext();){ + if(!f.call(o, a.next(), i++, a)){ + return false; // Boolean + } + } + }else{ + // object/dictionary + for(i in a){ + if(!(i in empty)){ + if(!f.call(o, a[i], i, a)){ + return false; // Boolean + } + } + } + } + return true; // Boolean + }, + some: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: tests whether some element in the array passes the test + // implemented by the provided function. + if(typeof a == "string"){ a = a.split(""); } + o = o || win.global; f = df.lambda(f); + var i, n; + if(lang.isArray(a)){ + // array + for(i = 0, n = a.length; i < n; ++i){ + if(f.call(o, a[i], i, a)){ + return true; // Boolean + } + } + }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ + // iterator + for(i = 0; a.hasNext();){ + if(f.call(o, a.next(), i++, a)){ + return true; // Boolean + } + } + }else{ + // object/dictionary + for(i in a){ + if(!(i in empty)){ + if(f.call(o, a[i], i, a)){ + return true; // Boolean + } + } + } + } + return false; // Boolean + } + }); + + return df; +}); + +}, +'dojox/charting/Theme':function(){ +define("dojox/charting/Theme", ["dojo/_base/lang", "dojo/_base/array","dojo/_base/declare","dojo/_base/Color", + "dojox/color/_base", "dojox/color/Palette", "dojox/lang/utils", "dojox/gfx/gradutils"], + function(lang, arr, declare, Color, colorX, Palette, dlu, dgg){ + + var Theme = declare("dojox.charting.Theme", null, { + // summary: + // A Theme is a pre-defined object, primarily JSON-based, that makes up the definitions to + // style a chart. + // + // description: + // While you can set up style definitions on a chart directly (usually through the various add methods + // on a dojox.charting.Chart object), a Theme simplifies this manual setup by allowing you to + // pre-define all of the various visual parameters of each element in a chart. + // + // Most of the properties of a Theme are straight-forward; if something is line-based (such as + // an axis or the ticks on an axis), they will be defined using basic stroke parameters. Likewise, + // if an element is primarily block-based (such as the background of a chart), it will be primarily + // fill-based. + // + // In addition (for convenience), a Theme definition does not have to contain the entire JSON-based + // structure. Each theme is built on top of a default theme (which serves as the basis for the theme + // "GreySkies"), and is mixed into the default theme object. This allows you to create a theme based, + // say, solely on colors for data series. + // + // Defining a new theme is relatively easy; see any of the themes in dojox.charting.themes for examples + // on how to define your own. + // + // When you set a theme on a chart, the theme itself is deep-cloned. This means that you cannot alter + // the theme itself after setting the theme value on a chart, and expect it to change your chart. If you + // are looking to make alterations to a theme for a chart, the suggestion would be to create your own + // theme, based on the one you want to use, that makes those alterations before it is applied to a chart. + // + // Finally, a Theme contains a number of functions to facilitate rendering operations on a chart--the main + // helper of which is the ~next~ method, in which a chart asks for the information for the next data series + // to be rendered. + // + // A note on colors: + // The Theme constructor was on the use of dojox.color.Palette (in general) for creating a visually distinct + // set of colors for usage in a chart. A palette is usually comprised of 5 different color definitions, and + // no more. If you have a need to render a chart with more than 5 data elements, you can simply "push" + // new color definitions into the theme's .color array. Make sure that you do that with the actual + // theme object from a Chart, and not in the theme itself (i.e. either do that before using .setTheme + // on a chart). + // + // example: + // The default theme (and structure) looks like so: + // | // all objects are structs used directly in dojox.gfx + // | chart:{ + // | stroke: null, + // | fill: "white", + // | pageStyle: null // suggested page style as an object suitable for dojo.style() + // | }, + // | plotarea:{ + // | stroke: null, + // | fill: "white" + // | }, + // | axis:{ + // | stroke: { // the axis itself + // | color: "#333", + // | width: 1 + // | }, + // | tick: { // used as a foundation for all ticks + // | color: "#666", + // | position: "center", + // | font: "normal normal normal 7pt Tahoma", // labels on axis + // | fontColor: "#333" // color of labels + // | }, + // | majorTick: { // major ticks on axis, and used for major gridlines + // | width: 1, + // | length: 6 + // | }, + // | minorTick: { // minor ticks on axis, and used for minor gridlines + // | width: 0.8, + // | length: 3 + // | }, + // | microTick: { // minor ticks on axis, and used for minor gridlines + // | width: 0.5, + // | length: 1 + // | } + // | }, + // | series: { + // | stroke: {width: 1.5, color: "#333"}, // line + // | outline: {width: 0.1, color: "#ccc"}, // outline + // | //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]}, + // | shadow: null, // no shadow + // | fill: "#ccc", // fill, if appropriate + // | font: "normal normal normal 8pt Tahoma", // if there's a label + // | fontColor: "#000" // color of labels + // | labelWiring: {width: 1, color: "#ccc"}, // connect marker and target data item(slice, column, bar...) + // | }, + // | marker: { // any markers on a series + // | symbol: "m-3,3 l3,-6 3,6 z", // symbol + // | stroke: {width: 1.5, color: "#333"}, // stroke + // | outline: {width: 0.1, color: "#ccc"}, // outline + // | shadow: null, // no shadow + // | fill: "#ccc", // fill if needed + // | font: "normal normal normal 8pt Tahoma", // label + // | fontColor: "#000" + // | }, + // | indicator: { + // | lineStroke: {width: 1.5, color: "#333"}, // line + // | lineOutline: {width: 0.1, color: "#ccc"}, // line outline + // | lineShadow: null, // no line shadow + // | stroke: {width: 1.5, color: "#333"}, // label background stroke + // | outline: {width: 0.1, color: "#ccc"}, // label background outline + // | shadow: null, // no label background shadow + // | fill: "#ccc", // label background fill + // | radius: 3, // radius of the label background + // | font: "normal normal normal 10pt Tahoma", // label font + // | fontColor: "#000" // label color + // | markerFill: "#ccc", // marker fill + // | markerSymbol: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", // marker symbol + // | markerStroke: {width: 1.5, color: "#333"}, // marker stroke + // | markerOutline: {width: 0.1, color: "#ccc"}, // marker outline + // | markerShadow: null, // no marker shadow + // | } + // + // example: + // Defining a new theme is pretty simple: + // | dojox.charting.themes.Grasslands = new dojox.charting.Theme({ + // | colors: [ "#70803a", "#dde574", "#788062", "#b1cc5d", "#eff2c2" ] + // | }); + // | + // | myChart.setTheme(dojox.charting.themes.Grasslands); + + shapeSpaces: {shape: 1, shapeX: 1, shapeY: 1}, + + constructor: function(kwArgs){ + // summary: + // Initialize a theme using the keyword arguments. Note that the arguments + // look like the example (above), and may include a few more parameters. + kwArgs = kwArgs || {}; + + // populate theme with defaults updating them if needed + var def = Theme.defaultTheme; + arr.forEach(["chart", "plotarea", "axis", "series", "marker", "indicator"], function(name){ + this[name] = lang.delegate(def[name], kwArgs[name]); + }, this); + + // personalize theme + if(kwArgs.seriesThemes && kwArgs.seriesThemes.length){ + this.colors = null; + this.seriesThemes = kwArgs.seriesThemes.slice(0); + }else{ + this.seriesThemes = null; + this.colors = (kwArgs.colors || Theme.defaultColors).slice(0); + } + this.markerThemes = null; + if(kwArgs.markerThemes && kwArgs.markerThemes.length){ + this.markerThemes = kwArgs.markerThemes.slice(0); + } + this.markers = kwArgs.markers ? lang.clone(kwArgs.markers) : lang.delegate(Theme.defaultMarkers); + + // set flags + this.noGradConv = kwArgs.noGradConv; + this.noRadialConv = kwArgs.noRadialConv; + if(kwArgs.reverseFills){ + this.reverseFills(); + } + + // private housekeeping + this._current = 0; + this._buildMarkerArray(); + }, + + clone: function(){ + // summary: + // Clone the current theme. + // returns: dojox.charting.Theme + // The cloned theme; any alterations made will not affect the original. + var theme = new Theme({ + // theme components + chart: this.chart, + plotarea: this.plotarea, + axis: this.axis, + series: this.series, + marker: this.marker, + // individual arrays + colors: this.colors, + markers: this.markers, + indicator: this.indicator, + seriesThemes: this.seriesThemes, + markerThemes: this.markerThemes, + // flags + noGradConv: this.noGradConv, + noRadialConv: this.noRadialConv + }); + // copy custom methods + arr.forEach( + ["clone", "clear", "next", "skip", "addMixin", "post", "getTick"], + function(name){ + if(this.hasOwnProperty(name)){ + theme[name] = this[name]; + } + }, + this + ); + return theme; // dojox.charting.Theme + }, + + clear: function(){ + // summary: + // Clear and reset the internal pointer to start fresh. + this._current = 0; + }, + + next: function(elementType, mixin, doPost){ + // summary: + // Get the next color or series theme. + // elementType: String? + // An optional element type (for use with series themes) + // mixin: Object? + // An optional object to mix into the theme. + // doPost: Boolean? + // A flag to post-process the results. + // returns: Object + // An object of the structure { series, marker, symbol } + var merge = dlu.merge, series, marker; + if(this.colors){ + series = lang.delegate(this.series); + marker = lang.delegate(this.marker); + var color = new Color(this.colors[this._current % this.colors.length]), old; + // modify the stroke + if(series.stroke && series.stroke.color){ + series.stroke = lang.delegate(series.stroke); + old = new Color(series.stroke.color); + series.stroke.color = new Color(color); + series.stroke.color.a = old.a; + }else{ + series.stroke = {color: color}; + } + if(marker.stroke && marker.stroke.color){ + marker.stroke = lang.delegate(marker.stroke); + old = new Color(marker.stroke.color); + marker.stroke.color = new Color(color); + marker.stroke.color.a = old.a; + }else{ + marker.stroke = {color: color}; + } + // modify the fill + if(!series.fill || series.fill.type){ + series.fill = color; + }else{ + old = new Color(series.fill); + series.fill = new Color(color); + series.fill.a = old.a; + } + if(!marker.fill || marker.fill.type){ + marker.fill = color; + }else{ + old = new Color(marker.fill); + marker.fill = new Color(color); + marker.fill.a = old.a; + } + }else{ + series = this.seriesThemes ? + merge(this.series, this.seriesThemes[this._current % this.seriesThemes.length]) : + this.series; + marker = this.markerThemes ? + merge(this.marker, this.markerThemes[this._current % this.markerThemes.length]) : + series; + } + + var symbol = marker && marker.symbol || this._markers[this._current % this._markers.length]; + + var theme = {series: series, marker: marker, symbol: symbol}; + + // advance the counter + ++this._current; + + if(mixin){ + theme = this.addMixin(theme, elementType, mixin); + } + if(doPost){ + theme = this.post(theme, elementType); + } + + return theme; // Object + }, + + skip: function(){ + // summary: + // Skip the next internal color. + ++this._current; + }, + + addMixin: function(theme, elementType, mixin, doPost){ + // summary: + // Add a mixin object to the passed theme and process. + // theme: dojox.charting.Theme + // The theme to mixin to. + // elementType: String + // The type of element in question. Can be "line", "bar" or "circle" + // mixin: Object|Array + // The object or objects to mix into the theme. + // doPost: Boolean + // If true, run the new theme through the post-processor. + // returns: dojox.charting.Theme + // The new theme. + if(lang.isArray(mixin)){ + arr.forEach(mixin, function(m){ + theme = this.addMixin(theme, elementType, m); + }, this); + }else{ + var t = {}; + if("color" in mixin){ + if(elementType == "line" || elementType == "area"){ + lang.setObject("series.stroke.color", mixin.color, t); + lang.setObject("marker.stroke.color", mixin.color, t); + }else{ + lang.setObject("series.fill", mixin.color, t); + } + } + arr.forEach(["stroke", "outline", "shadow", "fill", "font", "fontColor", "labelWiring"], function(name){ + var markerName = "marker" + name.charAt(0).toUpperCase() + name.substr(1), + b = markerName in mixin; + if(name in mixin){ + lang.setObject("series." + name, mixin[name], t); + if(!b){ + lang.setObject("marker." + name, mixin[name], t); + } + } + if(b){ + lang.setObject("marker." + name, mixin[markerName], t); + } + }); + if("marker" in mixin){ + t.symbol = mixin.marker; + } + theme = dlu.merge(theme, t); + } + if(doPost){ + theme = this.post(theme, elementType); + } + return theme; // dojox.charting.Theme + }, + + post: function(theme, elementType){ + // summary: + // Process any post-shape fills. + // theme: dojox.charting.Theme + // The theme to post process with. + // elementType: String + // The type of element being filled. Can be "bar" or "circle". + // returns: dojox.charting.Theme + // The post-processed theme. + var fill = theme.series.fill, t; + if(!this.noGradConv && this.shapeSpaces[fill.space] && fill.type == "linear"){ + if(elementType == "bar"){ + // transpose start and end points + t = { + x1: fill.y1, + y1: fill.x1, + x2: fill.y2, + y2: fill.x2 + }; + }else if(!this.noRadialConv && fill.space == "shape" && (elementType == "slice" || elementType == "circle")){ + // switch to radial + t = { + type: "radial", + cx: 0, + cy: 0, + r: 100 + }; + } + if(t){ + return dlu.merge(theme, {series: {fill: t}}); + } + } + return theme; // dojox.charting.Theme + }, + + getTick: function(name, mixin){ + // summary: + // Calculates and merges tick parameters. + // name: String + // Tick name, can be "major", "minor", or "micro". + // mixin: Object? + // Optional object to mix in to the tick. + var tick = this.axis.tick, tickName = name + "Tick", + merge = dlu.merge; + if(tick){ + if(this.axis[tickName]){ + tick = merge(tick, this.axis[tickName]); + } + }else{ + tick = this.axis[tickName]; + } + if(mixin){ + if(tick){ + if(mixin[tickName]){ + tick = merge(tick, mixin[tickName]); + } + }else{ + tick = mixin[tickName]; + } + } + return tick; // Object + }, + + inspectObjects: function(f){ + arr.forEach(["chart", "plotarea", "axis", "series", "marker", "indicator"], function(name){ + f(this[name]); + }, this); + if(this.seriesThemes){ + arr.forEach(this.seriesThemes, f); + } + if(this.markerThemes){ + arr.forEach(this.markerThemes, f); + } + }, + + reverseFills: function(){ + this.inspectObjects(function(o){ + if(o && o.fill){ + o.fill = dgg.reverse(o.fill); + } + }); + }, + + addMarker:function(/*String*/ name, /*String*/ segment){ + // summary: + // Add a custom marker to this theme. + // example: + // | myTheme.addMarker("Ellipse", foo); + this.markers[name] = segment; + this._buildMarkerArray(); + }, + + setMarkers:function(/*Object*/ obj){ + // summary: + // Set all the markers of this theme at once. obj should be a + // dictionary of keys and path segments. + // + // example: + // | myTheme.setMarkers({ "CIRCLE": foo }); + this.markers = obj; + this._buildMarkerArray(); + }, + + _buildMarkerArray: function(){ + this._markers = []; + for(var p in this.markers){ + this._markers.push(this.markers[p]); + } + } +}); + +/*===== +dojox.charting.Theme.__DefineColorArgs = function(num, colors, hue, saturation, low, high, base, generator){ + // summary: + // The arguments object that can be passed to define colors for a theme. + // num: Number? + // The number of colors to generate. Defaults to 5. + // colors: String[]|dojo.Color[]? + // A pre-defined set of colors; this is passed through to the Theme directly. + // hue: Number? + // A hue to base the generated colors from (a number from 0 - 359). + // saturation: Number? + // If a hue is passed, this is used for the saturation value (0 - 100). + // low: Number? + // An optional value to determine the lowest value used to generate a color (HSV model) + // high: Number? + // An optional value to determine the highest value used to generate a color (HSV model) + // base: String|dojo.Color? + // A base color to use if we are defining colors using dojox.color.Palette + // generator: String? + // The generator function name from dojox.color.Palette. + this.num = num; + this.colors = colors; + this.hue = hue; + this.saturation = saturation; + this.low = low; + this.high = high; + this.base = base; + this.generator = generator; +} +=====*/ +lang.mixin(Theme, { + defaultMarkers: { + CIRCLE: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", + SQUARE: "m-3,-3 l0,6 6,0 0,-6 z", + DIAMOND: "m0,-3 l3,3 -3,3 -3,-3 z", + CROSS: "m0,-3 l0,6 m-3,-3 l6,0", + X: "m-3,-3 l6,6 m0,-6 l-6,6", + TRIANGLE: "m-3,3 l3,-6 3,6 z", + TRIANGLE_INVERTED: "m-3,-3 l3,6 3,-6 z" + }, + + defaultColors:[ + // gray skies + "#54544c", "#858e94", "#6e767a", "#948585", "#474747" + ], + + defaultTheme: { + // all objects are structs used directly in dojox.gfx + chart:{ + stroke: null, + fill: "white", + pageStyle: null, + titleGap: 20, + titlePos: "top", + titleFont: "normal normal bold 14pt Tahoma", // labels on axis + titleFontColor: "#333" + }, + plotarea:{ + stroke: null, + fill: "white" + }, + // TODO: label rotation on axis + axis:{ + stroke: { // the axis itself + color: "#333", + width: 1 + }, + tick: { // used as a foundation for all ticks + color: "#666", + position: "center", + font: "normal normal normal 7pt Tahoma", // labels on axis + fontColor: "#333", // color of labels + titleGap: 15, + titleFont: "normal normal normal 11pt Tahoma", // labels on axis + titleFontColor: "#333", // color of labels + titleOrientation: "axis" // "axis": facing the axis, "away": facing away + }, + majorTick: { // major ticks on axis, and used for major gridlines + width: 1, + length: 6 + }, + minorTick: { // minor ticks on axis, and used for minor gridlines + width: 0.8, + length: 3 + }, + microTick: { // minor ticks on axis, and used for minor gridlines + width: 0.5, + length: 1 + } + }, + series: { + // used as a "main" theme for series, sThemes augment it + stroke: {width: 1.5, color: "#333"}, // line + outline: {width: 0.1, color: "#ccc"}, // outline + //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]}, + shadow: null, // no shadow + fill: "#ccc", // fill, if appropriate + font: "normal normal normal 8pt Tahoma", // if there's a label + fontColor: "#000", // color of labels + labelWiring: {width: 1, color: "#ccc"} // connect marker and target data item(slice, column, bar...) + }, + marker: { // any markers on a series + stroke: {width: 1.5, color: "#333"}, // stroke + outline: {width: 0.1, color: "#ccc"}, // outline + //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]}, + shadow: null, // no shadow + fill: "#ccc", // fill if needed + font: "normal normal normal 8pt Tahoma", // label + fontColor: "#000" + }, + indicator: { + lineStroke: {width: 1.5, color: "#333"}, + lineOutline: {width: 0.1, color: "#ccc"}, + lineShadow: null, + stroke: {width: 1.5, color: "#333"}, + outline: {width: 0.1, color: "#ccc"}, + shadow: null, + fill : "#ccc", + radius: 3, + font: "normal normal normal 10pt Tahoma", + fontColor: "#000", + markerFill: "#ccc", + markerSymbol: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", + markerStroke: {width: 1.5, color: "#333"}, + markerOutline: {width: 0.1, color: "#ccc"}, + markerShadow: null + } + }, + + defineColors: function(kwArgs){ + // summary: + // Generate a set of colors for the theme based on keyword + // arguments. + // kwArgs: dojox.charting.Theme.__DefineColorArgs + // The arguments object used to define colors. + // returns: dojo.Color[] + // An array of colors for use in a theme. + // + // example: + // | var colors = dojox.charting.Theme.defineColors({ + // | base: "#369", + // | generator: "compound" + // | }); + // + // example: + // | var colors = dojox.charting.Theme.defineColors({ + // | hue: 60, + // | saturation: 90, + // | low: 30, + // | high: 80 + // | }); + kwArgs = kwArgs || {}; + var l, c = [], n = kwArgs.num || 5; // the number of colors to generate + if(kwArgs.colors){ + // we have an array of colors predefined, so fix for the number of series. + l = kwArgs.colors.length; + for(var i = 0; i < n; i++){ + c.push(kwArgs.colors[i % l]); + } + return c; // dojo.Color[] + } + if(kwArgs.hue){ + // single hue, generate a set based on brightness + var s = kwArgs.saturation || 100, // saturation + st = kwArgs.low || 30, + end = kwArgs.high || 90; + // we'd like it to be a little on the darker side. + l = (end + st) / 2; + // alternately, use "shades" + return colorX.Palette.generate( + colorX.fromHsv(kwArgs.hue, s, l), "monochromatic" + ).colors; + } + if(kwArgs.generator){ + // pass a base color and the name of a generator + return colorX.Palette.generate(kwArgs.base, kwArgs.generator).colors; + } + return c; // dojo.Color[] + }, + + generateGradient: function(fillPattern, colorFrom, colorTo){ + var fill = lang.delegate(fillPattern); + fill.colors = [ + {offset: 0, color: colorFrom}, + {offset: 1, color: colorTo} + ]; + return fill; + }, + + generateHslColor: function(color, luminance){ + color = new Color(color); + var hsl = color.toHsl(), + result = colorX.fromHsl(hsl.h, hsl.s, luminance); + result.a = color.a; // add missing opacity + return result; + }, + + generateHslGradient: function(color, fillPattern, lumFrom, lumTo){ + color = new Color(color); + var hsl = color.toHsl(), + colorFrom = colorX.fromHsl(hsl.h, hsl.s, lumFrom), + colorTo = colorX.fromHsl(hsl.h, hsl.s, lumTo); + colorFrom.a = colorTo.a = color.a; // add missing opacity + return Theme.generateGradient(fillPattern, colorFrom, colorTo); // Object + } +}); + +return Theme; +}); + +}, +'dojox/charting/themes/common':function(){ +define("dojox/charting/themes/common", ["dojo/_base/lang"], function(lang){ + return lang.getObject("dojox.charting.themes", true); +}); + +}, +'dojox/charting/plot2d/common':function(){ +define("dojox/charting/plot2d/common", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/Color", + "dojox/gfx", "dojox/lang/functional", "../scaler/common"], + function(lang, arr, Color, g, df, sc){ + + var common = lang.getObject("dojox.charting.plot2d.common", true); + + return lang.mixin(common, { + doIfLoaded: sc.doIfLoaded, + makeStroke: function(stroke){ + if(!stroke){ return stroke; } + if(typeof stroke == "string" || stroke instanceof Color){ + stroke = {color: stroke}; + } + return g.makeParameters(g.defaultStroke, stroke); + }, + augmentColor: function(target, color){ + var t = new Color(target), + c = new Color(color); + c.a = t.a; + return c; + }, + augmentStroke: function(stroke, color){ + var s = common.makeStroke(stroke); + if(s){ + s.color = common.augmentColor(s.color, color); + } + return s; + }, + augmentFill: function(fill, color){ + var fc, c = new Color(color); + if(typeof fill == "string" || fill instanceof Color){ + return common.augmentColor(fill, color); + } + return fill; + }, + + defaultStats: { + vmin: Number.POSITIVE_INFINITY, vmax: Number.NEGATIVE_INFINITY, + hmin: Number.POSITIVE_INFINITY, hmax: Number.NEGATIVE_INFINITY + }, + + collectSimpleStats: function(series){ + var stats = lang.delegate(common.defaultStats); + for(var i = 0; i < series.length; ++i){ + var run = series[i]; + for(var j = 0; j < run.data.length; j++){ + if(run.data[j] !== null){ + if(typeof run.data[j] == "number"){ + // 1D case + var old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, i){ + if(val !== null){ + var x = i + 1, y = val; + if(isNaN(y)){ y = 0; } + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, y); + stats.vmax = Math.max(stats.vmax, y); + } + }); + } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + }else{ + // 2D case + var old_hmin = stats.hmin, old_hmax = stats.hmax, + old_vmin = stats.vmin, old_vmax = stats.vmax; + if(!("xmin" in run) || !("xmax" in run) || !("ymin" in run) || !("ymax" in run)){ + arr.forEach(run.data, function(val, i){ + if(val !== null){ + var x = "x" in val ? val.x : i + 1, y = val.y; + if(isNaN(x)){ x = 0; } + if(isNaN(y)){ y = 0; } + stats.hmin = Math.min(stats.hmin, x); + stats.hmax = Math.max(stats.hmax, x); + stats.vmin = Math.min(stats.vmin, y); + stats.vmax = Math.max(stats.vmax, y); + } + }); + } + if("xmin" in run){ stats.hmin = Math.min(old_hmin, run.xmin); } + if("xmax" in run){ stats.hmax = Math.max(old_hmax, run.xmax); } + if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } + if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } + } + + break; + } + } + } + return stats; + }, + + calculateBarSize: function(/* Number */ availableSize, /* Object */ opt, /* Number? */ clusterSize){ + if(!clusterSize){ + clusterSize = 1; + } + var gap = opt.gap, size = (availableSize - 2 * gap) / clusterSize; + if("minBarSize" in opt){ + size = Math.max(size, opt.minBarSize); + } + if("maxBarSize" in opt){ + size = Math.min(size, opt.maxBarSize); + } + size = Math.max(size, 1); + gap = (availableSize - size * clusterSize) / 2; + return {size: size, gap: gap}; // Object + }, + + collectStackedStats: function(series){ + // collect statistics + var stats = lang.clone(common.defaultStats); + if(series.length){ + // 1st pass: find the maximal length of runs + stats.hmin = Math.min(stats.hmin, 1); + stats.hmax = df.foldl(series, "seed, run -> Math.max(seed, run.data.length)", stats.hmax); + // 2nd pass: stack values + for(var i = 0; i < stats.hmax; ++i){ + var v = series[0].data[i]; + v = v && (typeof v == "number" ? v : v.y); + if(isNaN(v)){ v = 0; } + stats.vmin = Math.min(stats.vmin, v); + for(var j = 1; j < series.length; ++j){ + var t = series[j].data[i]; + t = t && (typeof t == "number" ? t : t.y); + if(isNaN(t)){ t = 0; } + v += t; + } + stats.vmax = Math.max(stats.vmax, v); + } + } + return stats; + }, + + curve: function(/* Number[] */a, /* Number|String */tension){ + // FIX for #7235, submitted by Enzo Michelangeli. + // Emulates the smoothing algorithms used in a famous, unnamed spreadsheet + // program ;) + var array = a.slice(0); + if(tension == "x") { + array[array.length] = arr[0]; // add a last element equal to the first, closing the loop + } + var p=arr.map(array, function(item, i){ + if(i==0){ return "M" + item.x + "," + item.y; } + if(!isNaN(tension)) { // use standard Dojo smoothing in tension is numeric + var dx=item.x-array[i-1].x, dy=array[i-1].y; + return "C"+(item.x-(tension-1)*(dx/tension))+","+dy+" "+(item.x-(dx/tension))+","+item.y+" "+item.x+","+item.y; + } else if(tension == "X" || tension == "x" || tension == "S") { + // use Excel "line smoothing" algorithm (http://xlrotor.com/resources/files.shtml) + var p0, p1 = array[i-1], p2 = array[i], p3; + var bz1x, bz1y, bz2x, bz2y; + var f = 1/6; + if(i==1) { + if(tension == "x") { + p0 = array[array.length-2]; + } else { // "tension == X || tension == "S" + p0 = p1; + } + f = 1/3; + } else { + p0 = array[i-2]; + } + if(i==(array.length-1)) { + if(tension == "x") { + p3 = array[1]; + } else { // "tension == X || tension == "S" + p3 = p2; + } + f = 1/3; + } else { + p3 = array[i+1]; + } + var p1p2 = Math.sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); + var p0p2 = Math.sqrt((p2.x-p0.x)*(p2.x-p0.x)+(p2.y-p0.y)*(p2.y-p0.y)); + var p1p3 = Math.sqrt((p3.x-p1.x)*(p3.x-p1.x)+(p3.y-p1.y)*(p3.y-p1.y)); + + var p0p2f = p0p2 * f; + var p1p3f = p1p3 * f; + + if(p0p2f > p1p2/2 && p1p3f > p1p2/2) { + p0p2f = p1p2/2; + p1p3f = p1p2/2; + } else if(p0p2f > p1p2/2) { + p0p2f = p1p2/2; + p1p3f = p1p2/2 * p1p3/p0p2; + } else if(p1p3f > p1p2/2) { + p1p3f = p1p2/2; + p0p2f = p1p2/2 * p0p2/p1p3; + } + + if(tension == "S") { + if(p0 == p1) { p0p2f = 0; } + if(p2 == p3) { p1p3f = 0; } + } + + bz1x = p1.x + p0p2f*(p2.x - p0.x)/p0p2; + bz1y = p1.y + p0p2f*(p2.y - p0.y)/p0p2; + bz2x = p2.x - p1p3f*(p3.x - p1.x)/p1p3; + bz2y = p2.y - p1p3f*(p3.y - p1.y)/p1p3; + } + return "C"+(bz1x+","+bz1y+" "+bz2x+","+bz2y+" "+p2.x+","+p2.y); + }); + return p.join(" "); + }, + + getLabel: function(/*Number*/number, /*Boolean*/fixed, /*Number*/precision){ + return sc.doIfLoaded("dojo/number", function(numberLib){ + return (fixed ? numberLib.format(number, {places : precision}) : + numberLib.format(number)) || ""; + }, function(){ + return fixed ? number.toFixed(precision) : number.toString(); + }); + } + }); +}); + +}, +'dijit/_Widget':function(){ +define("dijit/_Widget", [ + "dojo/aspect", // aspect.around + "dojo/_base/config", // config.isDebug + "dojo/_base/connect", // connect.connect + "dojo/_base/declare", // declare + "dojo/_base/kernel", // kernel.deprecated + "dojo/_base/lang", // lang.hitch + "dojo/query", + "dojo/ready", + "./registry", // registry.byNode + "./_WidgetBase", + "./_OnDijitClickMixin", + "./_FocusMixin", + "dojo/uacss", // browser sniffing (included for back-compat; subclasses may be using) + "./hccss" // high contrast mode sniffing (included to set CSS classes on <body>, module ret value unused) +], function(aspect, config, connect, declare, kernel, lang, query, ready, + registry, _WidgetBase, _OnDijitClickMixin, _FocusMixin){ + +/*===== + var _WidgetBase = dijit._WidgetBase; + var _OnDijitClickMixin = dijit._OnDijitClickMixin; + var _FocusMixin = dijit._FocusMixin; +=====*/ + + +// module: +// dijit/_Widget +// summary: +// Old base for widgets. New widgets should extend _WidgetBase instead + + +function connectToDomNode(){ + // summary: + // If user connects to a widget method === this function, then they will + // instead actually be connecting the equivalent event on this.domNode +} + +// Trap dojo.connect() calls to connectToDomNode methods, and redirect to _Widget.on() +function aroundAdvice(originalConnect){ + return function(obj, event, scope, method){ + if(obj && typeof event == "string" && obj[event] == connectToDomNode){ + return obj.on(event.substring(2).toLowerCase(), lang.hitch(scope, method)); + } + return originalConnect.apply(connect, arguments); + }; +} +aspect.around(connect, "connect", aroundAdvice); +if(kernel.connect){ + aspect.around(kernel, "connect", aroundAdvice); +} + +var _Widget = declare("dijit._Widget", [_WidgetBase, _OnDijitClickMixin, _FocusMixin], { + // summary: + // Base class for all Dijit widgets. + // + // Extends _WidgetBase, adding support for: + // - declaratively/programatically specifying widget initialization parameters like + // onMouseMove="foo" that call foo when this.domNode gets a mousemove event + // - ondijitclick + // Support new data-dojo-attach-event="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress + // - focus related functions + // In particular, the onFocus()/onBlur() callbacks. Driven internally by + // dijit/_base/focus.js. + // - deprecated methods + // - onShow(), onHide(), onClose() + // + // Also, by loading code in dijit/_base, turns on: + // - browser sniffing (putting browser id like .dj_ie on <html> node) + // - high contrast mode sniffing (add .dijit_a11y class to <body> if machine is in high contrast mode) + + + ////////////////// DEFERRED CONNECTS /////////////////// + + onClick: connectToDomNode, + /*===== + onClick: function(event){ + // summary: + // Connect to this function to receive notifications of mouse click events. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onDblClick: connectToDomNode, + /*===== + onDblClick: function(event){ + // summary: + // Connect to this function to receive notifications of mouse double click events. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onKeyDown: connectToDomNode, + /*===== + onKeyDown: function(event){ + // summary: + // Connect to this function to receive notifications of keys being pressed down. + // event: + // key Event + // tags: + // callback + }, + =====*/ + onKeyPress: connectToDomNode, + /*===== + onKeyPress: function(event){ + // summary: + // Connect to this function to receive notifications of printable keys being typed. + // event: + // key Event + // tags: + // callback + }, + =====*/ + onKeyUp: connectToDomNode, + /*===== + onKeyUp: function(event){ + // summary: + // Connect to this function to receive notifications of keys being released. + // event: + // key Event + // tags: + // callback + }, + =====*/ + onMouseDown: connectToDomNode, + /*===== + onMouseDown: function(event){ + // summary: + // Connect to this function to receive notifications of when the mouse button is pressed down. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onMouseMove: connectToDomNode, + /*===== + onMouseMove: function(event){ + // summary: + // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onMouseOut: connectToDomNode, + /*===== + onMouseOut: function(event){ + // summary: + // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onMouseOver: connectToDomNode, + /*===== + onMouseOver: function(event){ + // summary: + // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onMouseLeave: connectToDomNode, + /*===== + onMouseLeave: function(event){ + // summary: + // Connect to this function to receive notifications of when the mouse moves off of this widget. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onMouseEnter: connectToDomNode, + /*===== + onMouseEnter: function(event){ + // summary: + // Connect to this function to receive notifications of when the mouse moves onto this widget. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + onMouseUp: connectToDomNode, + /*===== + onMouseUp: function(event){ + // summary: + // Connect to this function to receive notifications of when the mouse button is released. + // event: + // mouse Event + // tags: + // callback + }, + =====*/ + + constructor: function(params){ + // extract parameters like onMouseMove that should connect directly to this.domNode + this._toConnect = {}; + for(var name in params){ + if(this[name] === connectToDomNode){ + this._toConnect[name.replace(/^on/, "").toLowerCase()] = params[name]; + delete params[name]; + } + } + }, + + postCreate: function(){ + this.inherited(arguments); + + // perform connection from this.domNode to user specified handlers (ex: onMouseMove) + for(var name in this._toConnect){ + this.on(name, this._toConnect[name]); + } + delete this._toConnect; + }, + + on: function(/*String*/ type, /*Function*/ func){ + if(this[this._onMap(type)] === connectToDomNode){ + // Use connect.connect() rather than on() to get handling for "onmouseenter" on non-IE, etc. + // Also, need to specify context as "this" rather than the default context of the DOMNode + return connect.connect(this.domNode, type.toLowerCase(), this, func); + } + return this.inherited(arguments); + }, + + _setFocusedAttr: function(val){ + // Remove this method in 2.0 (or sooner), just here to set _focused == focused, for back compat + // (but since it's a private variable we aren't required to keep supporting it). + this._focused = val; + this._set("focused", val); + }, + + ////////////////// DEPRECATED METHODS /////////////////// + + setAttribute: function(/*String*/ attr, /*anything*/ value){ + // summary: + // Deprecated. Use set() instead. + // tags: + // deprecated + kernel.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0"); + this.set(attr, value); + }, + + attr: function(/*String|Object*/name, /*Object?*/value){ + // summary: + // Set or get properties on a widget instance. + // name: + // The property to get or set. If an object is passed here and not + // a string, its keys are used as names of attributes to be set + // and the value of the object as values to set in the widget. + // value: + // Optional. If provided, attr() operates as a setter. If omitted, + // the current value of the named property is returned. + // description: + // This method is deprecated, use get() or set() directly. + + // Print deprecation warning but only once per calling function + if(config.isDebug){ + var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}), + caller = (arguments.callee.caller || "unknown caller").toString(); + if(!alreadyCalledHash[caller]){ + kernel.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " + + caller, "", "2.0"); + alreadyCalledHash[caller] = true; + } + } + + var args = arguments.length; + if(args >= 2 || typeof name === "object"){ // setter + return this.set.apply(this, arguments); + }else{ // getter + return this.get(name); + } + }, + + getDescendants: function(){ + // summary: + // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. + // This method should generally be avoided as it returns widgets declared in templates, which are + // supposed to be internal/hidden, but it's left here for back-compat reasons. + + kernel.deprecated(this.declaredClass+"::getDescendants() is deprecated. Use getChildren() instead.", "", "2.0"); + return this.containerNode ? query('[widgetId]', this.containerNode).map(registry.byNode) : []; // dijit._Widget[] + }, + + ////////////////// MISCELLANEOUS METHODS /////////////////// + + _onShow: function(){ + // summary: + // Internal method called when this widget is made visible. + // See `onShow` for details. + this.onShow(); + }, + + onShow: function(){ + // summary: + // Called when this widget becomes the selected pane in a + // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, + // `dijit.layout.AccordionContainer`, etc. + // + // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. + // tags: + // callback + }, + + onHide: function(){ + // summary: + // Called when another widget becomes the selected pane in a + // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, + // `dijit.layout.AccordionContainer`, etc. + // + // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. + // tags: + // callback + }, + + onClose: function(){ + // summary: + // Called when this widget is being displayed as a popup (ex: a Calendar popped + // up from a DateTextBox), and it is hidden. + // This is called from the dijit.popup code, and should not be called directly. + // + // Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses. + // Callback if a user tries to close the child. Child will be closed if this function returns true. + // tags: + // extension + + return true; // Boolean + } +}); + +// For back-compat, remove in 2.0. +if(!kernel.isAsync){ + ready(0, function(){ + var requires = ["dijit/_base"]; + require(requires); // use indirection so modules not rolled into a build + }); +} +return _Widget; +}); + +}, +'dijit/_FocusMixin':function(){ +define("dijit/_FocusMixin", [ + "./focus", + "./_WidgetBase", + "dojo/_base/declare", // declare + "dojo/_base/lang" // lang.extend +], function(focus, _WidgetBase, declare, lang){ + +/*===== + var _WidgetBase = dijit._WidgetBase; +=====*/ + + // module: + // dijit/_FocusMixin + // summary: + // Mixin to widget to provide _onFocus() and _onBlur() methods that + // fire when a widget or it's descendants get/lose focus + + // We don't know where _FocusMixin will occur in the inheritance chain, but we need the _onFocus()/_onBlur() below + // to be last in the inheritance chain, so mixin to _WidgetBase. + lang.extend(_WidgetBase, { + // focused: [readonly] Boolean + // This widget or a widget it contains has focus, or is "active" because + // it was recently clicked. + focused: false, + + onFocus: function(){ + // summary: + // Called when the widget becomes "active" because + // it or a widget inside of it either has focus, or has recently + // been clicked. + // tags: + // callback + }, + + onBlur: function(){ + // summary: + // Called when the widget stops being "active" because + // focus moved to something outside of it, or the user + // clicked somewhere outside of it, or the widget was + // hidden. + // tags: + // callback + }, + + _onFocus: function(){ + // summary: + // This is where widgets do processing for when they are active, + // such as changing CSS classes. See onFocus() for more details. + // tags: + // protected + this.onFocus(); + }, + + _onBlur: function(){ + // summary: + // This is where widgets do processing for when they stop being active, + // such as changing CSS classes. See onBlur() for more details. + // tags: + // protected + this.onBlur(); + } + }); + + return declare("dijit._FocusMixin", null, { + // summary: + // Mixin to widget to provide _onFocus() and _onBlur() methods that + // fire when a widget or it's descendants get/lose focus + + // flag that I want _onFocus()/_onBlur() notifications from focus manager + _focusManager: focus + }); + +}); + +}, +'dijit/_OnDijitClickMixin':function(){ +define("dijit/_OnDijitClickMixin", [ + "dojo/on", + "dojo/_base/array", // array.forEach + "dojo/keys", // keys.ENTER keys.SPACE + "dojo/_base/declare", // declare + "dojo/_base/sniff", // has("ie") + "dojo/_base/unload", // unload.addOnWindowUnload + "dojo/_base/window" // win.doc.addEventListener win.doc.attachEvent win.doc.detachEvent +], function(on, array, keys, declare, has, unload, win){ + + // module: + // dijit/_OnDijitClickMixin + // summary: + // Mixin so you can pass "ondijitclick" to this.connect() method, + // as a way to handle clicks by mouse, or by keyboard (SPACE/ENTER key) + + + // Keep track of where the last keydown event was, to help avoid generating + // spurious ondijitclick events when: + // 1. focus is on a <button> or <a> + // 2. user presses then releases the ENTER key + // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler + // 4. onkeyup event fires, causing the ondijitclick handler to fire + var lastKeyDownNode = null; + if(has("ie")){ + (function(){ + var keydownCallback = function(evt){ + lastKeyDownNode = evt.srcElement; + }; + win.doc.attachEvent('onkeydown', keydownCallback); + unload.addOnWindowUnload(function(){ + win.doc.detachEvent('onkeydown', keydownCallback); + }); + })(); + }else{ + win.doc.addEventListener('keydown', function(evt){ + lastKeyDownNode = evt.target; + }, true); + } + + // Custom a11yclick (a.k.a. ondijitclick) event + var a11yclick = function(node, listener){ + if(/input|button/i.test(node.nodeName)){ + // pass through, the browser already generates click event on SPACE/ENTER key + return on(node, "click", listener); + }else{ + // Don't fire the click event unless both the keydown and keyup occur on this node. + // Avoids problems where focus shifted to this node or away from the node on keydown, + // either causing this node to process a stray keyup event, or causing another node + // to get a stray keyup event. + + function clickKey(/*Event*/ e){ + return (e.keyCode == keys.ENTER || e.keyCode == keys.SPACE) && + !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey; + } + var handles = [ + on(node, "keypress", function(e){ + //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); + if(clickKey(e)){ + // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work + lastKeyDownNode = e.target; + + // Prevent viewport scrolling on space key in IE<9. + // (Reproducible on test_Button.html on any of the first dijit.form.Button examples) + // Do this onkeypress rather than onkeydown because onkeydown.preventDefault() will + // suppress the onkeypress event, breaking _HasDropDown + e.preventDefault(); + } + }), + + on(node, "keyup", function(e){ + //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", lastKeyDownNode, ", equality is ", (e.target === lastKeyDownNode)); + if(clickKey(e) && e.target == lastKeyDownNode){ // === breaks greasemonkey + //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert + lastKeyDownNode = null; + listener.call(this, e); + } + }), + + on(node, "click", function(e){ + // and connect for mouse clicks too (or touch-clicks on mobile) + listener.call(this, e); + }) + ]; + + return { + remove: function(){ + array.forEach(handles, function(h){ h.remove(); }); + } + }; + } + }; + + return declare("dijit._OnDijitClickMixin", null, { + connect: function( + /*Object|null*/ obj, + /*String|Function*/ event, + /*String|Function*/ method){ + // summary: + // Connects specified obj/event to specified method of this object + // and registers for disconnect() on widget destroy. + // description: + // Provide widget-specific analog to connect.connect, except with the + // implicit use of this widget as the target object. + // This version of connect also provides a special "ondijitclick" + // event which triggers on a click or space or enter keyup. + // Events connected with `this.connect` are disconnected upon + // destruction. + // returns: + // A handle that can be passed to `disconnect` in order to disconnect before + // the widget is destroyed. + // example: + // | var btn = new dijit.form.Button(); + // | // when foo.bar() is called, call the listener we're going to + // | // provide in the scope of btn + // | btn.connect(foo, "bar", function(){ + // | console.debug(this.toString()); + // | }); + // tags: + // protected + + return this.inherited(arguments, [obj, event == "ondijitclick" ? a11yclick : event, method]); + } + }); +}); + +}, +'dojo/cache':function(){ +define(["./_base/kernel", "./text"], function(dojo, text){ + // module: + // dojo/cache + // summary: + // The module defines dojo.cache by loading dojo/text. + + //dojo.cache is defined in dojo/text + return dojo.cache; +}); + +}, +'dojox/charting/plot2d/Bars':function(){ +define("dojox/charting/plot2d/Bars", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Base", "./common", + "dojox/gfx/fx", "dojox/lang/utils", "dojox/lang/functional", "dojox/lang/functional/reversed"], + function(dojo, lang, arr, declare, Base, dc, fx, du, df, dfr){ + + /*===== + dojo.declare("dojox.charting.plot2d.__BarCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, { + // summary: + // Additional keyword arguments for bar charts. + + // minBarSize: Number? + // The minimum size for a bar in pixels. Default is 1. + minBarSize: 1, + + // maxBarSize: Number? + // The maximum size for a bar in pixels. Default is 1. + maxBarSize: 1, + + // enableCache: Boolean? + // Whether the bars rect are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. Default false. + enableCache: false + }); + var Base = dojox.charting.plot2d.Base; + =====*/ + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.Bars", Base, { + // summary: + // The plot object representing a bar chart (horizontal bars). + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + gap: 0, // gap between columns in pixels + animate: null, // animate bars into place + enableCache: false + }, + optionalParams: { + minBarSize: 1, // minimal bar width in pixels + maxBarSize: 1, // maximal bar width in pixels + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for a bar chart. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__BarCtorArgs? + // An optional keyword arguments object to help define the plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + this.animate = this.opt.animate; + }, + + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectSimpleStats(this.series), t; + stats.hmin -= 0.5; + stats.hmax += 0.5; + t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; + t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; + return stats; + }, + + createRect: function(run, creator, params){ + var rect; + if(this.opt.enableCache && run._rectFreePool.length > 0){ + rect = run._rectFreePool.pop(); + rect.setShape(params); + // was cleared, add it back + creator.add(rect); + }else{ + rect = creator.createRect(params); + } + if(this.opt.enableCache){ + run._rectUsePool.push(rect); + } + return rect; + }, + + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.Bars + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.dirty = this.isDirty(); + this.resetEvents(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, height, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._hScaler.bounds.lower), + baselineWidth = ht(baseline), + events = this.events(); + f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt); + gap = f.gap; + height = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(this.opt.enableCache){ + run._rectFreePool = (run._rectFreePool?run._rectFreePool:[]).concat(run._rectUsePool?run._rectUsePool:[]); + run._rectUsePool = []; + } + var theme = t.next("bar", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + hv = ht(v), + width = hv - baselineWidth, + w = Math.abs(width), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "bar", value, true) : + t.post(theme, "bar"); + if(w >= 0 && height >= 1){ + var rect = { + x: offsets.l + (v < baseline ? hv : baselineWidth), + y: dim.height - offsets.b - vt(j + 1.5) + gap, + width: w, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = this.createRect(run, s, rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "bar", + index: j, + run: run, + shape: shape, + x: v, + y: j + 1.5 + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateBar(shape, offsets.l + baselineWidth, -w); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.Bars + }, + _animateBar: function(shape, hoffset, hsize){ + fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform: [ + {name: "translate", start: [hoffset - (hoffset/hsize), 0], end: [0, 0]}, + {name: "scale", start: [1/hsize, 1], end: [1, 1]}, + {name: "original"} + ] + }, this.animate)).play(); + } + }); +}); + +}, +'dojox/gfx/_base':function(){ +define("dojox/gfx/_base", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/Color", "dojo/_base/sniff", "dojo/_base/window", + "dojo/_base/array","dojo/dom", "dojo/dom-construct","dojo/dom-geometry"], + function(lang, html, Color, has, win, arr, dom, domConstruct, domGeom){ + // module: + // dojox/gfx + // summary: + // This module contains common core Graphics API used by different graphics renderers. + var g = lang.getObject("dojox.gfx", true), + b = g._base = {}; + /*===== g = dojox.gfx; b = dojox.gfx._base; =====*/ + + // candidates for dojox.style (work on VML and SVG nodes) + g._hasClass = function(/*DomNode*/node, /*String*/classStr){ + // summary: + // Returns whether or not the specified classes are a portion of the + // class list currently applied to the node. + // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean + var cls = node.getAttribute("className"); + return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean + }; + g._addClass = function(/*DomNode*/node, /*String*/classStr){ + // summary: + // Adds the specified classes to the end of the class list on the + // passed node. + var cls = node.getAttribute("className") || ""; + if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){ + node.setAttribute("className", cls + (cls ? " " : "") + classStr); + } + }; + g._removeClass = function(/*DomNode*/node, /*String*/classStr){ + // summary: Removes classes from node. + var cls = node.getAttribute("className"); + if(cls){ + node.setAttribute( + "className", + cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2") + ); + } + }; + + // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here) + + // derived from Morris John's emResized measurer + b._getFontMeasurements = function(){ + // summary: + // Returns an object that has pixel equivilents of standard font + // size values. + var heights = { + '1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0, + 'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0, + 'xx-large': 0 + }; + var p; + + if(has("ie")){ + // we do a font-size fix if and only if one isn't applied already. + // NOTE: If someone set the fontSize on the HTML Element, this will kill it. + win.doc.documentElement.style.fontSize="100%"; + } + + // set up the measuring node. + var div = domConstruct.create("div", {style: { + position: "absolute", + left: "0", + top: "-100px", + width: "30px", + height: "1000em", + borderWidth: "0", + margin: "0", + padding: "0", + outline: "none", + lineHeight: "1", + overflow: "hidden" + }}, win.body()); + + // do the measurements. + for(p in heights){ + div.style.fontSize = p; + heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000; + } + + win.body().removeChild(div); + return heights; //object + }; + + var fontMeasurements = null; + + b._getCachedFontMeasurements = function(recalculate){ + if(recalculate || !fontMeasurements){ + fontMeasurements = b._getFontMeasurements(); + } + return fontMeasurements; + }; + + // candidate for dojox.html.metrics + + var measuringNode = null, empty = {}; + b._getTextBox = function( /*String*/ text, + /*Object*/ style, + /*String?*/ className){ + var m, s, al = arguments.length; + var i; + if(!measuringNode){ + measuringNode = domConstruct.create("div", {style: { + position: "absolute", + top: "-10000px", + left: "0" + }}, win.body()); + } + m = measuringNode; + // reset styles + m.className = ""; + s = m.style; + s.borderWidth = "0"; + s.margin = "0"; + s.padding = "0"; + s.outline = "0"; + // set new style + if(al > 1 && style){ + for(i in style){ + if(i in empty){ continue; } + s[i] = style[i]; + } + } + // set classes + if(al > 2 && className){ + m.className = className; + } + // take a measure + m.innerHTML = text; + + if(m["getBoundingClientRect"]){ + var bcr = m.getBoundingClientRect(); + return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)}; + }else{ + return domGeom.getMarginBox(m); + } + }; + + // candidate for dojo.dom + + var uniqueId = 0; + b._getUniqueId = function(){ + // summary: returns a unique string for use with any DOM element + var id; + do{ + id = dojo._scopeName + "xUnique" + (++uniqueId); + }while(dom.byId(id)); + return id; + }; + + lang.mixin(g, { + // summary: + // defines constants, prototypes, and utility functions for the core Graphics API + + // default shapes, which are used to fill in missing parameters + defaultPath: { + // summary: + // Defines the default Path prototype object. + type: "path", + // type: String + // Specifies this object is a Path, default value 'path'. + path: "" + // path: String + // The path commands. See W32C SVG 1.0 specification. + // Defaults to empty string value. + }, + defaultPolyline: { + // summary: + // Defines the default PolyLine prototype. + type: "polyline", + // type: String + // Specifies this object is a PolyLine, default value 'polyline'. + points: [] + // points: Array + // An array of point objects [{x:0,y:0},...] defining the default polyline's line segments. Value is an empty array []. + }, + defaultRect: { + // summary: + // Defines the default Rect prototype. + type: "rect", + // type: String + // Specifies this default object is a type of Rect. Value is 'rect' + x: 0, + // x: Number + // The X coordinate of the default rectangles position, value 0. + y: 0, + // y: Number + // The Y coordinate of the default rectangle's position, value 0. + width: 100, + // width: Number + // The width of the default rectangle, value 100. + height: 100, + // height: Number + // The height of the default rectangle, value 100. + r: 0 + // r: Number + // The corner radius for the default rectangle, value 0. + }, + defaultEllipse: { + // summary: + // Defines the default Ellipse prototype. + type: "ellipse", + // type: String + // Specifies that this object is a type of Ellipse, value is 'ellipse' + cx: 0, + // cx: Number + // The X coordinate of the center of the ellipse, default value 0. + cy: 0, + // cy: Number + // The Y coordinate of the center of the ellipse, default value 0. + rx: 200, + // rx: Number + // The radius of the ellipse in the X direction, default value 200. + ry: 100 + // ry: Number + // The radius of the ellipse in the Y direction, default value 200. + }, + defaultCircle: { + // summary: + // An object defining the default Circle prototype. + type: "circle", + // type: String + // Specifies this object is a circle, value 'circle' + cx: 0, + // cx: Number + // The X coordinate of the center of the circle, default value 0. + cy: 0, + // cy: Number + // The Y coordinate of the center of the circle, default value 0. + r: 100 + // r: Number + // The radius, default value 100. + }, + defaultLine: { + // summary: + // An pbject defining the default Line prototype. + type: "line", + // type: String + // Specifies this is a Line, value 'line' + x1: 0, + // x1: Number + // The X coordinate of the start of the line, default value 0. + y1: 0, + // y1: Number + // The Y coordinate of the start of the line, default value 0. + x2: 100, + // x2: Number + // The X coordinate of the end of the line, default value 100. + y2: 100 + // y2: Number + // The Y coordinate of the end of the line, default value 100. + }, + defaultImage: { + // summary: + // Defines the default Image prototype. + type: "image", + // type: String + // Specifies this object is an image, value 'image'. + x: 0, + // x: Number + // The X coordinate of the image's position, default value 0. + y: 0, + // y: Number + // The Y coordinate of the image's position, default value 0. + width: 0, + // width: Number + // The width of the image, default value 0. + height: 0, + // height:Number + // The height of the image, default value 0. + src: "" + // src: String + // The src url of the image, defaults to empty string. + }, + defaultText: { + // summary: + // Defines the default Text prototype. + type: "text", + // type: String + // Specifies this is a Text shape, value 'text'. + x: 0, + // x: Number + // The X coordinate of the text position, default value 0. + y: 0, + // y: Number + // The Y coordinate of the text position, default value 0. + text: "", + // text: String + // The text to be displayed, default value empty string. + align: "start", + // align: String + // The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'. + decoration: "none", + // decoration: String + // The text decoration , one of 'none', ... . Default value 'none'. + rotated: false, + // rotated: Boolean + // Whether the text is rotated, boolean default value false. + kerning: true + // kerning: Boolean + // Whether kerning is used on the text, boolean default value true. + }, + defaultTextPath: { + // summary: + // Defines the default TextPath prototype. + type: "textpath", + // type: String + // Specifies this is a TextPath, value 'textpath'. + text: "", + // text: String + // The text to be displayed, default value empty string. + align: "start", + // align: String + // The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'. + decoration: "none", + // decoration: String + // The text decoration , one of 'none', ... . Default value 'none'. + rotated: false, + // rotated: Boolean + // Whether the text is rotated, boolean default value false. + kerning: true + // kerning: Boolean + // Whether kerning is used on the text, boolean default value true. + }, + + // default stylistic attributes + defaultStroke: { + // summary: + // A stroke defines stylistic properties that are used when drawing a path. + // This object defines the default Stroke prototype. + type: "stroke", + // type: String + // Specifies this object is a type of Stroke, value 'stroke'. + color: "black", + // color: String + // The color of the stroke, default value 'black'. + style: "solid", + // style: String + // The style of the stroke, one of 'solid', ... . Default value 'solid'. + width: 1, + // width: Number + // The width of a stroke, default value 1. + cap: "butt", + // cap: String + // The endcap style of the path. One of 'butt', 'round', ... . Default value 'butt'. + join: 4 + // join: Number + // The join style to use when combining path segments. Default value 4. + }, + defaultLinearGradient: { + // summary: + // An object defining the default stylistic properties used for Linear Gradient fills. + // Linear gradients are drawn along a virtual line, which results in appearance of a rotated pattern in a given direction/orientation. + type: "linear", + // type: String + // Specifies this object is a Linear Gradient, value 'linear' + x1: 0, + // x1: Number + // The X coordinate of the start of the virtual line along which the gradient is drawn, default value 0. + y1: 0, + // y1: Number + // The Y coordinate of the start of the virtual line along which the gradient is drawn, default value 0. + x2: 100, + // x2: Number + // The X coordinate of the end of the virtual line along which the gradient is drawn, default value 100. + y2: 100, + // y2: Number + // The Y coordinate of the end of the virtual line along which the gradient is drawn, default value 100. + colors: [ + { offset: 0, color: "black" }, { offset: 1, color: "white" } + ] + // colors: Array + // An array of colors at given offsets (from the start of the line). The start of the line is + // defined at offest 0 with the end of the line at offset 1. + // Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white. + }, + defaultRadialGradient: { + // summary: + // An object specifying the default properties for RadialGradients using in fills patterns. + type: "radial", + // type: String + // Specifies this is a RadialGradient, value 'radial' + cx: 0, + // cx: Number + // The X coordinate of the center of the radial gradient, default value 0. + cy: 0, + // cy: Number + // The Y coordinate of the center of the radial gradient, default value 0. + r: 100, + // r: Number + // The radius to the end of the radial gradient, default value 100. + colors: [ + { offset: 0, color: "black" }, { offset: 1, color: "white" } + ] + // colors: Array + // An array of colors at given offsets (from the center of the radial gradient). + // The center is defined at offest 0 with the outer edge of the gradient at offset 1. + // Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white. + }, + defaultPattern: { + // summary: + // An object specifying the default properties for a Pattern using in fill operations. + type: "pattern", + // type: String + // Specifies this object is a Pattern, value 'pattern'. + x: 0, + // x: Number + // The X coordinate of the position of the pattern, default value is 0. + y: 0, + // y: Number + // The Y coordinate of the position of the pattern, default value is 0. + width: 0, + // width: Number + // The width of the pattern image, default value is 0. + height: 0, + // height: Number + // The height of the pattern image, default value is 0. + src: "" + // src: String + // A url specifing the image to use for the pattern. + }, + defaultFont: { + // summary: + // An object specifying the default properties for a Font used in text operations. + type: "font", + // type: String + // Specifies this object is a Font, value 'font'. + style: "normal", + // style: String + // The font style, one of 'normal', 'bold', default value 'normal'. + variant: "normal", + // variant: String + // The font variant, one of 'normal', ... , default value 'normal'. + weight: "normal", + // weight: String + // The font weight, one of 'normal', ..., default value 'normal'. + size: "10pt", + // size: String + // The font size (including units), default value '10pt'. + family: "serif" + // family: String + // The font family, one of 'serif', 'sanserif', ..., default value 'serif'. + }, + + getDefault: (function(){ + // summary: + // Returns a function used to access default memoized prototype objects (see them defined above). + var typeCtorCache = {}; + // a memoized delegate() + return function(/*String*/ type){ + var t = typeCtorCache[type]; + if(t){ + return new t(); + } + t = typeCtorCache[type] = new Function(); + t.prototype = g[ "default" + type ]; + return new t(); + } + })(), + + normalizeColor: function(/*dojo.Color|Array|string|Object*/ color){ + // summary: + // converts any legal color representation to normalized + // dojo.Color object + return (color instanceof Color) ? color : new Color(color); // dojo.Color + }, + normalizeParameters: function(existed, update){ + // summary: + // updates an existing object with properties from an 'update' + // object + // existed: Object + // the target object to be updated + // update: Object + // the 'update' object, whose properties will be used to update + // the existed object + var x; + if(update){ + var empty = {}; + for(x in existed){ + if(x in update && !(x in empty)){ + existed[x] = update[x]; + } + } + } + return existed; // Object + }, + makeParameters: function(defaults, update){ + // summary: + // copies the original object, and all copied properties from the + // 'update' object + // defaults: Object + // the object to be cloned before updating + // update: Object + // the object, which properties are to be cloned during updating + var i = null; + if(!update){ + // return dojo.clone(defaults); + return lang.delegate(defaults); + } + var result = {}; + for(i in defaults){ + if(!(i in result)){ + result[i] = lang.clone((i in update) ? update[i] : defaults[i]); + } + } + return result; // Object + }, + formatNumber: function(x, addSpace){ + // summary: converts a number to a string using a fixed notation + // x: Number + // number to be converted + // addSpace: Boolean + // whether to add a space before a positive number + var val = x.toString(); + if(val.indexOf("e") >= 0){ + val = x.toFixed(4); + }else{ + var point = val.indexOf("."); + if(point >= 0 && val.length - point > 5){ + val = x.toFixed(4); + } + } + if(x < 0){ + return val; // String + } + return addSpace ? " " + val : val; // String + }, + // font operations + makeFontString: function(font){ + // summary: converts a font object to a CSS font string + // font: Object: font object (see dojox.gfx.defaultFont) + return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object + }, + splitFontString: function(str){ + // summary: + // converts a CSS font string to a font object + // description: + // Converts a CSS font string to a gfx font object. The CSS font + // string components should follow the W3C specified order + // (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand): + // style, variant, weight, size, optional line height (will be + // ignored), and family. + // str: String + // a CSS font string + var font = g.getDefault("Font"); + var t = str.split(/\s+/); + do{ + if(t.length < 5){ break; } + font.style = t[0]; + font.variant = t[1]; + font.weight = t[2]; + var i = t[3].indexOf("/"); + font.size = i < 0 ? t[3] : t[3].substring(0, i); + var j = 4; + if(i < 0){ + if(t[4] == "/"){ + j = 6; + }else if(t[4].charAt(0) == "/"){ + j = 5; + } + } + if(j < t.length){ + font.family = t.slice(j).join(" "); + } + }while(false); + return font; // Object + }, + // length operations + cm_in_pt: 72 / 2.54, + // cm_in_pt: Number + // points per centimeter (constant) + mm_in_pt: 7.2 / 2.54, + // mm_in_pt: Number + // points per millimeter (constant) + px_in_pt: function(){ + // summary: returns the current number of pixels per point. + return g._base._getCachedFontMeasurements()["12pt"] / 12; // Number + }, + pt2px: function(len){ + // summary: converts points to pixels + // len: Number + // a value in points + return len * g.px_in_pt(); // Number + }, + px2pt: function(len){ + // summary: converts pixels to points + // len: Number + // a value in pixels + return len / g.px_in_pt(); // Number + }, + normalizedLength: function(len) { + // summary: converts any length value to pixels + // len: String + // a length, e.g., '12pc' + if(len.length === 0){ return 0; } + if(len.length > 2){ + var px_in_pt = g.px_in_pt(); + var val = parseFloat(len); + switch(len.slice(-2)){ + case "px": return val; + case "pt": return val * px_in_pt; + case "in": return val * 72 * px_in_pt; + case "pc": return val * 12 * px_in_pt; + case "mm": return val * g.mm_in_pt * px_in_pt; + case "cm": return val * g.cm_in_pt * px_in_pt; + } + } + return parseFloat(len); // Number + }, + + pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, + // pathVmlRegExp: RegExp + // a constant regular expression used to split a SVG/VML path into primitive components + pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, + // pathVmlRegExp: RegExp + // a constant regular expression used to split a SVG/VML path into primitive components + + equalSources: function(a /*Object*/, b /*Object*/){ + // summary: compares event sources, returns true if they are equal + // a: first event source + // b: event source to compare against a + return a && b && a === b; + }, + + switchTo: function(renderer/*String|Object*/){ + // summary: switch the graphics implementation to the specified renderer. + // renderer: + // Either the string name of a renderer (eg. 'canvas', 'svg, ...) or the renderer + // object to switch to. + var ns = typeof renderer == "string" ? g[renderer] : renderer; + if(ns){ + arr.forEach(["Group", "Rect", "Ellipse", "Circle", "Line", + "Polyline", "Image", "Text", "Path", "TextPath", + "Surface", "createSurface", "fixTarget"], function(name){ + g[name] = ns[name]; + }); + } + } + }); + return g; // defaults object api +}); + +}, +'dijit/focus':function(){ +define("dijit/focus", [ + "dojo/aspect", + "dojo/_base/declare", // declare + "dojo/dom", // domAttr.get dom.isDescendant + "dojo/dom-attr", // domAttr.get dom.isDescendant + "dojo/dom-construct", // connect to domConstruct.empty, domConstruct.destroy + "dojo/Evented", + "dojo/_base/lang", // lang.hitch + "dojo/on", + "dojo/ready", + "dojo/_base/sniff", // has("ie") + "dojo/Stateful", + "dojo/_base/unload", // unload.addOnWindowUnload + "dojo/_base/window", // win.body + "dojo/window", // winUtils.get + "./a11y", // a11y.isTabNavigable + "./registry", // registry.byId + "." // to set dijit.focus +], function(aspect, declare, dom, domAttr, domConstruct, Evented, lang, on, ready, has, Stateful, unload, win, winUtils, + a11y, registry, dijit){ + + // module: + // dijit/focus + // summary: + // Returns a singleton that tracks the currently focused node, and which widgets are currently "active". + +/*===== + dijit.focus = { + // summary: + // Tracks the currently focused node, and which widgets are currently "active". + // Access via require(["dijit/focus"], function(focus){ ... }). + // + // A widget is considered active if it or a descendant widget has focus, + // or if a non-focusable node of this widget or a descendant was recently clicked. + // + // Call focus.watch("curNode", callback) to track the current focused DOMNode, + // or focus.watch("activeStack", callback) to track the currently focused stack of widgets. + // + // Call focus.on("widget-blur", func) or focus.on("widget-focus", ...) to monitor when + // when widgets become active/inactive + // + // Finally, focus(node) will focus a node, suppressing errors if the node doesn't exist. + + // curNode: DomNode + // Currently focused item on screen + curNode: null, + + // activeStack: dijit._Widget[] + // List of currently active widgets (focused widget and it's ancestors) + activeStack: [], + + registerIframe: function(iframe){ + // summary: + // Registers listeners on the specified iframe so that any click + // or focus event on that iframe (or anything in it) is reported + // as a focus/click event on the <iframe> itself. + // description: + // Currently only used by editor. + // returns: + // Handle with remove() method to deregister. + }, + + registerWin: function(targetWindow, effectiveNode){ + // summary: + // Registers listeners on the specified window (either the main + // window or an iframe's window) to detect when the user has clicked somewhere + // or focused somewhere. + // description: + // Users should call registerIframe() instead of this method. + // targetWindow: Window? + // If specified this is the window associated with the iframe, + // i.e. iframe.contentWindow. + // effectiveNode: DOMNode? + // If specified, report any focus events inside targetWindow as + // an event on effectiveNode, rather than on evt.target. + // returns: + // Handle with remove() method to deregister. + } + }; +=====*/ + + var FocusManager = declare([Stateful, Evented], { + // curNode: DomNode + // Currently focused item on screen + curNode: null, + + // activeStack: dijit._Widget[] + // List of currently active widgets (focused widget and it's ancestors) + activeStack: [], + + constructor: function(){ + // Don't leave curNode/prevNode pointing to bogus elements + var check = lang.hitch(this, function(node){ + if(dom.isDescendant(this.curNode, node)){ + this.set("curNode", null); + } + if(dom.isDescendant(this.prevNode, node)){ + this.set("prevNode", null); + } + }); + aspect.before(domConstruct, "empty", check); + aspect.before(domConstruct, "destroy", check); + }, + + registerIframe: function(/*DomNode*/ iframe){ + // summary: + // Registers listeners on the specified iframe so that any click + // or focus event on that iframe (or anything in it) is reported + // as a focus/click event on the <iframe> itself. + // description: + // Currently only used by editor. + // returns: + // Handle with remove() method to deregister. + return this.registerWin(iframe.contentWindow, iframe); + }, + + registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){ + // summary: + // Registers listeners on the specified window (either the main + // window or an iframe's window) to detect when the user has clicked somewhere + // or focused somewhere. + // description: + // Users should call registerIframe() instead of this method. + // targetWindow: + // If specified this is the window associated with the iframe, + // i.e. iframe.contentWindow. + // effectiveNode: + // If specified, report any focus events inside targetWindow as + // an event on effectiveNode, rather than on evt.target. + // returns: + // Handle with remove() method to deregister. + + // TODO: make this function private in 2.0; Editor/users should call registerIframe(), + + var _this = this; + var mousedownListener = function(evt){ + _this._justMouseDowned = true; + setTimeout(function(){ _this._justMouseDowned = false; }, 0); + + // workaround weird IE bug where the click is on an orphaned node + // (first time clicking a Select/DropDownButton inside a TooltipDialog) + if(has("ie") && evt && evt.srcElement && evt.srcElement.parentNode == null){ + return; + } + + _this._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse"); + }; + + // Listen for blur and focus events on targetWindow's document. + // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble + // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers + // fire. + // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because + // (at least for FF) the focus event doesn't fire on <html> or <body>. + var doc = has("ie") ? targetWindow.document.documentElement : targetWindow.document; + if(doc){ + if(has("ie")){ + targetWindow.document.body.attachEvent('onmousedown', mousedownListener); + var activateListener = function(evt){ + // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1, + // ignore those events + var tag = evt.srcElement.tagName.toLowerCase(); + if(tag == "#document" || tag == "body"){ return; } + + // Previous code called _onTouchNode() for any activate event on a non-focusable node. Can + // probably just ignore such an event as it will be handled by onmousedown handler above, but + // leaving the code for now. + if(a11y.isTabNavigable(evt.srcElement)){ + _this._onFocusNode(effectiveNode || evt.srcElement); + }else{ + _this._onTouchNode(effectiveNode || evt.srcElement); + } + }; + doc.attachEvent('onactivate', activateListener); + var deactivateListener = function(evt){ + _this._onBlurNode(effectiveNode || evt.srcElement); + }; + doc.attachEvent('ondeactivate', deactivateListener); + + return { + remove: function(){ + targetWindow.document.detachEvent('onmousedown', mousedownListener); + doc.detachEvent('onactivate', activateListener); + doc.detachEvent('ondeactivate', deactivateListener); + doc = null; // prevent memory leak (apparent circular reference via closure) + } + }; + }else{ + doc.body.addEventListener('mousedown', mousedownListener, true); + doc.body.addEventListener('touchstart', mousedownListener, true); + var focusListener = function(evt){ + _this._onFocusNode(effectiveNode || evt.target); + }; + doc.addEventListener('focus', focusListener, true); + var blurListener = function(evt){ + _this._onBlurNode(effectiveNode || evt.target); + }; + doc.addEventListener('blur', blurListener, true); + + return { + remove: function(){ + doc.body.removeEventListener('mousedown', mousedownListener, true); + doc.body.removeEventListener('touchstart', mousedownListener, true); + doc.removeEventListener('focus', focusListener, true); + doc.removeEventListener('blur', blurListener, true); + doc = null; // prevent memory leak (apparent circular reference via closure) + } + }; + } + } + }, + + _onBlurNode: function(/*DomNode*/ /*===== node =====*/){ + // summary: + // Called when focus leaves a node. + // Usually ignored, _unless_ it *isn't* followed by touching another node, + // which indicates that we tabbed off the last field on the page, + // in which case every widget is marked inactive + this.set("prevNode", this.curNode); + this.set("curNode", null); + + if(this._justMouseDowned){ + // the mouse down caused a new widget to be marked as active; this blur event + // is coming late, so ignore it. + return; + } + + // if the blur event isn't followed by a focus event then mark all widgets as inactive. + if(this._clearActiveWidgetsTimer){ + clearTimeout(this._clearActiveWidgetsTimer); + } + this._clearActiveWidgetsTimer = setTimeout(lang.hitch(this, function(){ + delete this._clearActiveWidgetsTimer; + this._setStack([]); + this.prevNode = null; + }), 100); + }, + + _onTouchNode: function(/*DomNode*/ node, /*String*/ by){ + // summary: + // Callback when node is focused or mouse-downed + // node: + // The node that was touched. + // by: + // "mouse" if the focus/touch was caused by a mouse down event + + // ignore the recent blurNode event + if(this._clearActiveWidgetsTimer){ + clearTimeout(this._clearActiveWidgetsTimer); + delete this._clearActiveWidgetsTimer; + } + + // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem) + var newStack=[]; + try{ + while(node){ + var popupParent = domAttr.get(node, "dijitPopupParent"); + if(popupParent){ + node=registry.byId(popupParent).domNode; + }else if(node.tagName && node.tagName.toLowerCase() == "body"){ + // is this the root of the document or just the root of an iframe? + if(node === win.body()){ + // node is the root of the main document + break; + } + // otherwise, find the iframe this node refers to (can't access it via parentNode, + // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit + node=winUtils.get(node.ownerDocument).frameElement; + }else{ + // if this node is the root node of a widget, then add widget id to stack, + // except ignore clicks on disabled widgets (actually focusing a disabled widget still works, + // to support MenuItem) + var id = node.getAttribute && node.getAttribute("widgetId"), + widget = id && registry.byId(id); + if(widget && !(by == "mouse" && widget.get("disabled"))){ + newStack.unshift(id); + } + node=node.parentNode; + } + } + }catch(e){ /* squelch */ } + + this._setStack(newStack, by); + }, + + _onFocusNode: function(/*DomNode*/ node){ + // summary: + // Callback when node is focused + + if(!node){ + return; + } + + if(node.nodeType == 9){ + // Ignore focus events on the document itself. This is here so that + // (for example) clicking the up/down arrows of a spinner + // (which don't get focus) won't cause that widget to blur. (FF issue) + return; + } + + this._onTouchNode(node); + + if(node == this.curNode){ return; } + this.set("curNode", node); + }, + + _setStack: function(/*String[]*/ newStack, /*String*/ by){ + // summary: + // The stack of active widgets has changed. Send out appropriate events and records new stack. + // newStack: + // array of widget id's, starting from the top (outermost) widget + // by: + // "mouse" if the focus/touch was caused by a mouse down event + + var oldStack = this.activeStack; + this.set("activeStack", newStack); + + // compare old stack to new stack to see how many elements they have in common + for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){ + if(oldStack[nCommon] != newStack[nCommon]){ + break; + } + } + + var widget; + // for all elements that have gone out of focus, set focused=false + for(var i=oldStack.length-1; i>=nCommon; i--){ + widget = registry.byId(oldStack[i]); + if(widget){ + widget._hasBeenBlurred = true; // TODO: used by form widgets, should be moved there + widget.set("focused", false); + if(widget._focusManager == this){ + widget._onBlur(by); + } + this.emit("widget-blur", widget, by); + } + } + + // for all element that have come into focus, set focused=true + for(i=nCommon; i<newStack.length; i++){ + widget = registry.byId(newStack[i]); + if(widget){ + widget.set("focused", true); + if(widget._focusManager == this){ + widget._onFocus(by); + } + this.emit("widget-focus", widget, by); + } + } + }, + + focus: function(node){ + // summary: + // Focus the specified node, suppressing errors if they occur + if(node){ + try{ node.focus(); }catch(e){/*quiet*/} + } + } + }); + + var singleton = new FocusManager(); + + // register top window and all the iframes it contains + ready(function(){ + var handle = singleton.registerWin(win.doc.parentWindow || win.doc.defaultView); + if(has("ie")){ + unload.addOnWindowUnload(function(){ + handle.remove(); + handle = null; + }) + } + }); + + // Setup dijit.focus as a pointer to the singleton but also (for backwards compatibility) + // as a function to set focus. + dijit.focus = function(node){ + singleton.focus(node); // indirection here allows dijit/_base/focus.js to override behavior + }; + for(var attr in singleton){ + if(!/^_/.test(attr)){ + dijit.focus[attr] = typeof singleton[attr] == "function" ? lang.hitch(singleton, attr) : singleton[attr]; + } + } + singleton.watch(function(attr, oldVal, newVal){ + dijit.focus[attr] = newVal; + }); + + return singleton; +}); + +}, +'dojox/charting/widget/Legend':function(){ +define("dojox/charting/widget/Legend", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/declare", "dijit/_Widget", "dojox/gfx","dojo/_base/array", + "dojox/lang/functional", "dojox/lang/functional/array", "dojox/lang/functional/fold", + "dojo/dom", "dojo/dom-construct", "dojo/dom-class","dijit/_base/manager"], + function(lang, html, declare, Widget, gfx, arrayUtil, df, dfa, dff, + dom, domFactory, domClass, widgetManager){ +/*===== +var Widget = dijit._Widget; +=====*/ + + var REVERSED_SERIES = /\.(StackedColumns|StackedAreas|ClusteredBars)$/; + + return declare("dojox.charting.widget.Legend", Widget, { + // summary: A legend for a chart. A legend contains summary labels for + // each series of data contained in the chart. + // + // Set the horizontal attribute to boolean false to layout legend labels vertically. + // Set the horizontal attribute to a number to layout legend labels in horizontal + // rows each containing that number of labels (except possibly the last row). + // + // (Line or Scatter charts (colored lines with shape symbols) ) + // -o- Series1 -X- Series2 -v- Series3 + // + // (Area/Bar/Pie charts (letters represent colors)) + // [a] Series1 [b] Series2 [c] Series3 + + chartRef: "", + horizontal: true, + swatchSize: 18, + + legendBody: null, + + postCreate: function(){ + if(!this.chart){ + if(!this.chartRef){ return; } + this.chart = widgetManager.byId(this.chartRef); + if(!this.chart){ + var node = dom.byId(this.chartRef); + if(node){ + this.chart = widgetManager.byNode(node); + }else{ + console.log("Could not find chart instance with id: " + this.chartRef); + return; + } + } + this.series = this.chart.chart.series; + }else{ + this.series = this.chart.series; + } + + this.refresh(); + }, + buildRendering: function(){ + this.domNode = domFactory.create("table", + {role: "group", "aria-label": "chart legend", "class": "dojoxLegendNode"}); + this.legendBody = domFactory.create("tbody", null, this.domNode); + this.inherited(arguments); + }, + refresh: function(){ + // summary: regenerates the legend to reflect changes to the chart + + // cleanup + if(this._surfaces){ + arrayUtil.forEach(this._surfaces, function(surface){ + surface.destroy(); + }); + } + this._surfaces = []; + while(this.legendBody.lastChild){ + domFactory.destroy(this.legendBody.lastChild); + } + + if(this.horizontal){ + domClass.add(this.domNode, "dojoxLegendHorizontal"); + // make a container <tr> + this._tr = domFactory.create("tr", null, this.legendBody); + this._inrow = 0; + } + + var s = this.series; + if(s.length == 0){ + return; + } + if(s[0].chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie"){ + var t = s[0].chart.stack[0]; + if(typeof t.run.data[0] == "number"){ + var filteredRun = df.map(t.run.data, "Math.max(x, 0)"); + if(df.every(filteredRun, "<= 0")){ + return; + } + var slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); + arrayUtil.forEach(slices, function(x, i){ + this._addLabel(t.dyn[i], t._getLabel(x * 100) + "%"); + }, this); + }else{ + arrayUtil.forEach(t.run.data, function(x, i){ + this._addLabel(t.dyn[i], x.legend || x.text || x.y); + }, this); + } + }else{ + if(this._isReversal()){ + s = s.slice(0).reverse(); + } + arrayUtil.forEach(s, function(x){ + this._addLabel(x.dyn, x.legend || x.name); + }, this); + } + }, + _addLabel: function(dyn, label){ + // create necessary elements + var wrapper = domFactory.create("td"), + icon = domFactory.create("div", null, wrapper), + text = domFactory.create("label", null, wrapper), + div = domFactory.create("div", { + style: { + "width": this.swatchSize + "px", + "height":this.swatchSize + "px", + "float": "left" + } + }, icon); + domClass.add(icon, "dojoxLegendIcon dijitInline"); + domClass.add(text, "dojoxLegendText"); + // create a skeleton + if(this._tr){ + // horizontal + this._tr.appendChild(wrapper); + if(++this._inrow === this.horizontal){ + // make a fresh container <tr> + this._tr = domFactory.create("tr", null, this.legendBody); + this._inrow = 0; + } + }else{ + // vertical + var tr = domFactory.create("tr", null, this.legendBody); + tr.appendChild(wrapper); + } + + // populate the skeleton + this._makeIcon(div, dyn); + text.innerHTML = String(label); + text.dir = this.getTextDir(label, text.dir); + }, + _makeIcon: function(div, dyn){ + var mb = { h: this.swatchSize, w: this.swatchSize }; + var surface = gfx.createSurface(div, mb.w, mb.h); + this._surfaces.push(surface); + if(dyn.fill){ + // regions + surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}). + setFill(dyn.fill).setStroke(dyn.stroke); + }else if(dyn.stroke || dyn.marker){ + // draw line + var line = {x1: 0, y1: mb.h / 2, x2: mb.w, y2: mb.h / 2}; + if(dyn.stroke){ + surface.createLine(line).setStroke(dyn.stroke); + } + if(dyn.marker){ + // draw marker on top + var c = {x: mb.w / 2, y: mb.h / 2}; + if(dyn.stroke){ + surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}). + setFill(dyn.stroke.color).setStroke(dyn.stroke); + }else{ + surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}). + setFill(dyn.color).setStroke(dyn.color); + } + } + }else{ + // nothing + surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}). + setStroke("black"); + surface.createLine({x1: 2, y1: 2, x2: mb.w - 2, y2: mb.h - 2}).setStroke("black"); + surface.createLine({x1: 2, y1: mb.h - 2, x2: mb.w - 2, y2: 2}).setStroke("black"); + } + }, + _isReversal: function(){ + return (!this.horizontal) && arrayUtil.some(this.chart.stack, function(item){ + return REVERSED_SERIES.test(item.declaredClass); + }); + } + }); +}); + +}, +'dojox/charting/plot2d/StackedLines':function(){ +define("dojox/charting/plot2d/StackedLines", ["dojo/_base/declare", "./Stacked"], function(declare, Stacked){ +/*===== +var Stacked = dojox.charting.plot2d.Stacked; +=====*/ + return declare("dojox.charting.plot2d.StackedLines", Stacked, { + // summary: + // A convenience object to create a stacked line chart. + constructor: function(){ + // summary: + // Force our Stacked base to be lines only. + this.opt.lines = true; + } + }); +}); + +}, +'dojox/charting/plot2d/StackedColumns':function(){ +define("dojox/charting/plot2d/StackedColumns", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Columns", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/functional/sequence"], + function(lang, arr, declare, Columns, dc, df, dfr, dfs){ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); +/*===== +var Columns = dojox.charting.plot2d.Columns; +=====*/ + return declare("dojox.charting.plot2d.StackedColumns", Columns, { + // summary: + // The plot object representing a stacked column chart (vertical bars). + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + var stats = dc.collectStackedStats(this.series); + this._maxRunLength = stats.hmax; + stats.hmin -= 0.5; + stats.hmax += 0.5; + return stats; + }, + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.StackedColumns + // A reference to this plot for functional chaining. + if(this._maxRunLength <= 0){ + return this; + } + + // stack all values + var acc = df.repeat(this._maxRunLength, "-> 0", 0); + for(var i = 0; i < this.series.length; ++i){ + var run = this.series[i]; + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] += v; + } + } + } + // draw runs in backwards + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, width, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + events = this.events(); + f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); + gap = f.gap; + width = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("column", [this.opt, run]), s = run.group, + eventSeries = new Array(acc.length); + for(var j = 0; j < acc.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = acc[j], + height = vt(v), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "column", value, true) : + t.post(theme, "column"); + if(width >= 1 && height >= 0){ + var rect = { + x: offsets.l + ht(j + 0.5) + gap, + y: dim.height - offsets.b - vt(v), + width: width, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "column", + index: j, + run: run, + shape: shape, + x: j + 0.5, + y: v + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateColumn(shape, dim.height - offsets.b, height); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + // update the accumulator + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y; + if(isNaN(v)){ v = 0; } + acc[j] -= v; + } + } + } + this.dirty = false; + return this; // dojox.charting.plot2d.StackedColumns + } + }); +}); + +}, +'dojox/charting/Series':function(){ +define(["dojo/_base/lang", "dojo/_base/declare", "./Element"], + function(lang, declare, Element){ + /*===== + dojox.charting.__SeriesCtorArgs = function(plot){ + // summary: + // An optional arguments object that can be used in the Series constructor. + // plot: String? + // The plot (by name) that this series belongs to. + this.plot = plot; + } + + var Element = dojox.charting.Element; + =====*/ + return declare("dojox.charting.Series", Element, { + // summary: + // An object representing a series of data for plotting on a chart. + constructor: function(chart, data, kwArgs){ + // summary: + // Create a new data series object for use within charting. + // chart: dojox.charting.Chart + // The chart that this series belongs to. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + // kwArgs: dojox.charting.__SeriesCtorArgs? + // An optional keyword arguments object to set details for this series. + lang.mixin(this, kwArgs); + if(typeof this.plot != "string"){ this.plot = "default"; } + this.update(data); + }, + + clear: function(){ + // summary: + // Clear the calculated additional parameters set on this series. + this.dyn = {}; + }, + + update: function(data){ + // summary: + // Set data and make this object dirty, so it can be redrawn. + // data: Array|Object: + // The array of data points (either numbers or objects) that + // represents the data to be drawn. Or it can be an object. In + // the latter case, it should have a property "data" (an array), + // destroy(), and setSeriesObject(). + if(lang.isArray(data)){ + this.data = data; + }else{ + this.source = data; + this.data = this.source.data; + if(this.source.setSeriesObject){ + this.source.setSeriesObject(this); + } + } + this.dirty = true; + this.clear(); + } + }); + +}); + +}, +'dojox/charting/plot2d/Default':function(){ +define("dojox/charting/plot2d/Default", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", + "./Base", "./common", "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils", "dojox/gfx/fx"], + function(lang, declare, arr, Base, dc, df, dfr, du, fx){ + + /*===== + dojo.declare("dojox.charting.plot2d.__DefaultCtorArgs", dojox.charting.plot2d.__PlotCtorArgs, { + // summary: + // The arguments used for any/most plots. + + // hAxis: String? + // The horizontal axis name. + hAxis: "x", + + // vAxis: String? + // The vertical axis name + vAxis: "y", + + // lines: Boolean? + // Whether or not to draw lines on this plot. Defaults to true. + lines: true, + + // areas: Boolean? + // Whether or not to draw areas on this plot. Defaults to false. + areas: false, + + // markers: Boolean? + // Whether or not to draw markers at data points on this plot. Default is false. + markers: false, + + // tension: Number|String? + // Whether or not to apply 'tensioning' to the lines on this chart. + // Options include a number, "X", "x", or "S"; if a number is used, the + // simpler bezier curve calculations are used to draw the lines. If X, x or S + // is used, the more accurate smoothing algorithm is used. + tension: "", + + // animate: Boolean? + // Whether or not to animate the chart to place. + animate: false, + + // stroke: dojox.gfx.Stroke? + // An optional stroke to use for any series on the plot. + stroke: {}, + + // outline: dojox.gfx.Stroke? + // An optional stroke used to outline any series on the plot. + outline: {}, + + // shadow: dojox.gfx.Stroke? + // An optional stroke to use to draw any shadows for a series on a plot. + shadow: {}, + + // fill: dojox.gfx.Fill? + // Any fill to be used for elements on the plot (such as areas). + fill: {}, + + // font: String? + // A font definition to be used for labels and other text-based elements on the plot. + font: "", + + // fontColor: String|dojo.Color? + // The color to be used for any text-based elements on the plot. + fontColor: "", + + // markerStroke: dojo.gfx.Stroke? + // An optional stroke to use for any markers on the plot. + markerStroke: {}, + + // markerOutline: dojo.gfx.Stroke? + // An optional outline to use for any markers on the plot. + markerOutline: {}, + + // markerShadow: dojo.gfx.Stroke? + // An optional shadow to use for any markers on the plot. + markerShadow: {}, + + // markerFill: dojo.gfx.Fill? + // An optional fill to use for any markers on the plot. + markerFill: {}, + + // markerFont: String? + // An optional font definition to use for any markers on the plot. + markerFont: "", + + // markerFontColor: String|dojo.Color? + // An optional color to use for any marker text on the plot. + markerFontColor: "", + + // enableCache: Boolean? + // Whether the markers are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. Default false. + enableCache: false + }); + + var Base = dojox.charting.plot2d.Base; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + var DEFAULT_ANIMATION_LENGTH = 1200; // in ms + + return declare("dojox.charting.plot2d.Default", Base, { + defaultParams: { + hAxis: "x", // use a horizontal axis named "x" + vAxis: "y", // use a vertical axis named "y" + lines: true, // draw lines + areas: false, // draw areas + markers: false, // draw markers + tension: "", // draw curved lines (tension is "X", "x", or "S") + animate: false, // animate chart to place + enableCache: false + }, + optionalParams: { + // theme component + stroke: {}, + outline: {}, + shadow: {}, + fill: {}, + font: "", + fontColor: "", + markerStroke: {}, + markerOutline: {}, + markerShadow: {}, + markerFill: {}, + markerFont: "", + markerFontColor: "" + }, + + constructor: function(chart, kwArgs){ + // summary: + // Return a new plot. + // chart: dojox.charting.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs? + // An optional arguments object to help define this plot. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + this.series = []; + this.hAxis = this.opt.hAxis; + this.vAxis = this.opt.vAxis; + + // animation properties + this.animate = this.opt.animate; + }, + + createPath: function(run, creator, params){ + var path; + if(this.opt.enableCache && run._pathFreePool.length > 0){ + path = run._pathFreePool.pop(); + path.setShape(params); + // was cleared, add it back + creator.add(path); + }else{ + path = creator.createPath(params); + } + if(this.opt.enableCache){ + run._pathUsePool.push(path); + } + return path; + }, + + render: function(dim, offsets){ + // summary: + // Render/draw everything on this plot. + // dim: Object + // An object of the form { width, height } + // offsets: Object + // An object of the form { l, r, t, b } + // returns: dojox.charting.plot2d.Default + // A reference to this plot for functional chaining. + + // make sure all the series is not modified + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + this.group.setTransform(null); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, stroke, outline, marker, events = this.events(); + + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i]; + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + if(this.opt.enableCache){ + run._pathFreePool = (run._pathFreePool?run._pathFreePool:[]).concat(run._pathUsePool?run._pathUsePool:[]); + run._pathUsePool = []; + } + if(!run.data.length){ + run.dirty = false; + t.skip(); + continue; + } + + var theme = t.next(this.opt.areas ? "area" : "line", [this.opt, run], true), + s = run.group, rsegments = [], startindexes = [], rseg = null, lpoly, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + eventSeries = this._eventSeries[run.name] = new Array(run.data.length); + + // optim works only for index based case + var indexed = typeof run.data[0] == "number"; + var min = indexed?Math.max(0, Math.floor(this._hScaler.bounds.from - 1)):0, + max = indexed?Math.min(run.data.length, Math.ceil(this._hScaler.bounds.to)):run.data.length; + + // split the run data into dense segments (each containing no nulls) + for(var j = min; j < max; j++){ + if(run.data[j] != null){ + if(!rseg){ + rseg = []; + startindexes.push(j); + rsegments.push(rseg); + } + rseg.push(run.data[j]); + }else{ + rseg = null; + } + } + + for(var seg = 0; seg < rsegments.length; seg++){ + if(typeof rsegments[seg][0] == "number"){ + lpoly = arr.map(rsegments[seg], function(v, i){ + return { + x: ht(i + startindexes[seg] + 1) + offsets.l, + y: dim.height - offsets.b - vt(v) + }; + }, this); + }else{ + lpoly = arr.map(rsegments[seg], function(v, i){ + return { + x: ht(v.x) + offsets.l, + y: dim.height - offsets.b - vt(v.y) + }; + }, this); + } + + var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : ""; + + if(this.opt.areas && lpoly.length > 1){ + var fill = theme.series.fill; + var apoly = lang.clone(lpoly); + if(this.opt.tension){ + var apath = "L" + apoly[apoly.length-1].x + "," + (dim.height - offsets.b) + + " L" + apoly[0].x + "," + (dim.height - offsets.b) + + " L" + apoly[0].x + "," + apoly[0].y; + run.dyn.fill = s.createPath(lpath + " " + apath).setFill(fill).getFill(); + } else { + apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); + apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); + apoly.push(lpoly[0]); + run.dyn.fill = s.createPolyline(apoly).setFill(fill).getFill(); + } + } + if(this.opt.lines || this.opt.markers){ + // need a stroke + stroke = theme.series.stroke; + if(theme.series.outline){ + outline = run.dyn.outline = dc.makeStroke(theme.series.outline); + outline.width = 2 * outline.width + stroke.width; + } + } + if(this.opt.markers){ + run.dyn.marker = theme.symbol; + } + var frontMarkers = null, outlineMarkers = null, shadowMarkers = null; + if(stroke && theme.series.shadow && lpoly.length > 1){ + var shadow = theme.series.shadow, + spoly = arr.map(lpoly, function(c){ + return {x: c.x + shadow.dx, y: c.y + shadow.dy}; + }); + if(this.opt.lines){ + if(this.opt.tension){ + run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadow).getStroke(); + } else { + run.dyn.shadow = s.createPolyline(spoly).setStroke(shadow).getStroke(); + } + } + if(this.opt.markers && theme.marker.shadow){ + shadow = theme.marker.shadow; + shadowMarkers = arr.map(spoly, function(c){ + return this.createPath(run, s, "M" + c.x + " " + c.y + " " + theme.symbol). + setStroke(shadow).setFill(shadow.color); + }, this); + } + } + if(this.opt.lines && lpoly.length > 1){ + if(outline){ + if(this.opt.tension){ + run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke(); + } else { + run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke(); + } + } + if(this.opt.tension){ + run.dyn.stroke = s.createPath(lpath).setStroke(stroke).getStroke(); + } else { + run.dyn.stroke = s.createPolyline(lpoly).setStroke(stroke).getStroke(); + } + } + if(this.opt.markers){ + frontMarkers = new Array(lpoly.length); + outlineMarkers = new Array(lpoly.length); + outline = null; + if(theme.marker.outline){ + outline = dc.makeStroke(theme.marker.outline); + outline.width = 2 * outline.width + (theme.marker.stroke ? theme.marker.stroke.width : 0); + } + arr.forEach(lpoly, function(c, i){ + var path = "M" + c.x + " " + c.y + " " + theme.symbol; + if(outline){ + outlineMarkers[i] = this.createPath(run, s, path).setStroke(outline); + } + frontMarkers[i] = this.createPath(run, s, path).setStroke(theme.marker.stroke).setFill(theme.marker.fill); + }, this); + run.dyn.markerFill = theme.marker.fill; + run.dyn.markerStroke = theme.marker.stroke; + if(events){ + arr.forEach(frontMarkers, function(s, i){ + var o = { + element: "marker", + index: i + startindexes[seg], + run: run, + shape: s, + outline: outlineMarkers[i] || null, + shadow: shadowMarkers && shadowMarkers[i] || null, + cx: lpoly[i].x, + cy: lpoly[i].y + }; + if(typeof rsegments[seg][0] == "number"){ + o.x = i + startindexes[seg] + 1; + o.y = rsegments[seg][i]; + }else{ + o.x = rsegments[seg][i].x; + o.y = rsegments[seg][i].y; + } + this._connectEvents(o); + eventSeries[i + startindexes[seg]] = o; + }, this); + }else{ + delete this._eventSeries[run.name]; + } + } + } + run.dirty = false; + } + if(this.animate){ + // grow from the bottom + var plotGroup = this.group; + fx.animateTransform(lang.delegate({ + shape: plotGroup, + duration: DEFAULT_ANIMATION_LENGTH, + transform:[ + {name:"translate", start: [0, dim.height - offsets.b], end: [0, 0]}, + {name:"scale", start: [1, 0], end:[1, 1]}, + {name:"original"} + ] + }, this.animate)).play(); + } + this.dirty = false; + return this; // dojox.charting.plot2d.Default + } + }); +}); + +}, +'dijit/main':function(){ +define("dijit/main", [ + "dojo/_base/kernel" +], function(dojo){ + // module: + // dijit + // summary: + // The dijit package main module + + return dojo.dijit; +}); + +}, +'dojox/charting/plot2d/Base':function(){ +define("dojox/charting/plot2d/Base", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", + "../Element", "./_PlotEvents", "dojo/_base/array", + "../scaler/primitive", "./common", "dojox/gfx/fx"], + function(lang, declare, hub, Element, PlotEvents, arr, primitive, common, fx){ +/*===== +var Element = dojox.charting.Element; +var PlotEvents = dojox.charting.plot2d._PlotEvents; +dojox.charting.plot2d.__PlotCtorArgs = function(){ + // summary: + // The base keyword arguments object for plot constructors. + // Note that the parameters for this may change based on the + // specific plot type (see the corresponding plot type for + // details). +} +=====*/ +return declare("dojox.charting.plot2d.Base", [Element, PlotEvents], { + constructor: function(chart, kwArgs){ + // summary: + // Create a base plot for charting. + // chart: dojox.chart.Chart + // The chart this plot belongs to. + // kwArgs: dojox.charting.plot2d.__PlotCtorArgs? + // An optional arguments object to help define the plot. + this.zoom = null, + this.zoomQueue = []; // zooming action task queue + this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0}; + }, + clear: function(){ + // summary: + // Clear out all of the information tied to this plot. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.series = []; + this._hAxis = null; + this._vAxis = null; + this.dirty = true; + return this; // dojox.charting.plot2d.Base + }, + setAxis: function(axis){ + // summary: + // Set an axis for this plot. + // axis: dojox.charting.axis2d.Base + // The axis to set. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + if(axis){ + this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; + } + return this; // dojox.charting.plot2d.Base + }, + toPage: function(coord){ + // summary: + // Compute page coordinates from plot axis data coordinates. + // coord: Object? + // The coordinates in plot axis data coordinate space. For cartesian charts that is of the following form: + // `{ hAxisName: 50, vAxisName: 200 }` + // If not provided return the tranform method instead of the result of the transformation. + // returns: Object + // The resulting page pixel coordinates. That is of the following form: + // `{ x: 50, y: 200 }` + var ah = this._hAxis, av = this._vAxis, + sh = ah.getScaler(), sv = av.getScaler(), + th = sh.scaler.getTransformerFromModel(sh), + tv = sv.scaler.getTransformerFromModel(sv), + c = this.chart.getCoords(), + o = this.chart.offsets, dim = this.chart.dim; + var t = function(coord){ + var r = {}; + r.x = th(coord[ah.name]) + c.x + o.l; + r.y = c.y + dim.height - o.b - tv(coord[av.name]); + return r; + }; + // if no coord return the function so that we can capture the current transforms + // and reuse them later on + return coord?t(coord):t; + }, + toData: function(coord){ + // summary: + // Compute plot axis data coordinates from page coordinates. + // coord: Object + // The pixel coordinate in page coordinate space. That is of the following form: + // `{ x: 50, y: 200 }` + // If not provided return the tranform method instead of the result of the transformation. + // returns: Object + // The resulting plot axis data coordinates. For cartesian charts that is of the following form: + // `{ hAxisName: 50, vAxisName: 200 }` + var ah = this._hAxis, av = this._vAxis, + sh = ah.getScaler(), sv = av.getScaler(), + th = sh.scaler.getTransformerFromPlot(sh), + tv = sv.scaler.getTransformerFromPlot(sv), + c = this.chart.getCoords(), + o = this.chart.offsets, dim = this.chart.dim; + var t = function(coord){ + var r = {}; + r[ah.name] = th(coord.x - c.x - o.l); + r[av.name] = tv(c.y + dim.height - coord.y - o.b); + return r; + }; + // if no coord return the function so that we can capture the current transforms + // and reuse them later on + return coord?t(coord):t; + }, + addSeries: function(run){ + // summary: + // Add a data series to this plot. + // run: dojox.charting.Series + // The series to be added. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.series.push(run); + return this; // dojox.charting.plot2d.Base + }, + getSeriesStats: function(){ + // summary: + // Calculate the min/max on all attached series in both directions. + // returns: Object + // {hmin, hmax, vmin, vmax} min/max in both directions. + return common.collectSimpleStats(this.series); + }, + calculateAxes: function(dim){ + // summary: + // Stub function for running the axis calculations (depricated). + // dim: Object + // An object of the form { width, height } + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + this.initializeScalers(dim, this.getSeriesStats()); + return this; // dojox.charting.plot2d.Base + }, + isDirty: function(){ + // summary: + // Returns whether or not this plot needs to be rendered. + // returns: Boolean + // The state of the plot. + return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean + }, + isDataDirty: function(){ + // summary: + // Returns whether or not any of this plot's data series need to be rendered. + // returns: Boolean + // Flag indicating if any of this plot's series are invalid and need rendering. + return arr.some(this.series, function(item){ return item.dirty; }); // Boolean + }, + performZoom: function(dim, offsets){ + // summary: + // Create/alter any zooming windows on this plot. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + + // get current zooming various + var vs = this._vAxis.scale || 1, + hs = this._hAxis.scale || 1, + vOffset = dim.height - offsets.b, + hBounds = this._hScaler.bounds, + xOffset = (hBounds.from - hBounds.lower) * hBounds.scale, + vBounds = this._vScaler.bounds, + yOffset = (vBounds.from - vBounds.lower) * vBounds.scale, + // get incremental zooming various + rVScale = vs / this.lastWindow.vscale, + rHScale = hs / this.lastWindow.hscale, + rXOffset = (this.lastWindow.xoffset - xOffset)/ + ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale), + rYOffset = (yOffset - this.lastWindow.yoffset)/ + ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale), + + shape = this.group, + anim = fx.animateTransform(lang.delegate({ + shape: shape, + duration: 1200, + transform:[ + {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]}, + {name:"scale", start:[1, 1], end: [rHScale, rVScale]}, + {name:"original"}, + {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]} + ]}, this.zoom)); + + lang.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset}); + //add anim to zooming action queue, + //in order to avoid several zooming action happened at the same time + this.zoomQueue.push(anim); + //perform each anim one by one in zoomQueue + hub.connect(anim, "onEnd", this, function(){ + this.zoom = null; + this.zoomQueue.shift(); + if(this.zoomQueue.length > 0){ + this.zoomQueue[0].play(); + } + }); + if(this.zoomQueue.length == 1){ + this.zoomQueue[0].play(); + } + return this; // dojox.charting.plot2d.Base + }, + render: function(dim, offsets){ + // summary: + // Render the plot on the chart. + // dim: Object + // An object of the form { width, height }. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + return this; // dojox.charting.plot2d.Base + }, + getRequiredColors: function(){ + // summary: + // Get how many data series we have, so we know how many colors to use. + // returns: Number + // The number of colors needed. + return this.series.length; // Number + }, + initializeScalers: function(dim, stats){ + // summary: + // Initializes scalers using attached axes. + // dim: Object: + // Size of a plot area in pixels as {width, height}. + // stats: Object: + // Min/max of data in both directions as {hmin, hmax, vmin, vmax}. + // returns: dojox.charting.plot2d.Base + // A reference to this plot for functional chaining. + if(this._hAxis){ + if(!this._hAxis.initialized()){ + this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); + } + this._hScaler = this._hAxis.getScaler(); + }else{ + this._hScaler = primitive.buildScaler(stats.hmin, stats.hmax, dim.width); + } + if(this._vAxis){ + if(!this._vAxis.initialized()){ + this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); + } + this._vScaler = this._vAxis.getScaler(); + }else{ + this._vScaler = primitive.buildScaler(stats.vmin, stats.vmax, dim.height); + } + return this; // dojox.charting.plot2d.Base + } +}); +}); + +}, +'dojox/charting/action2d/Tooltip':function(){ +define("dojox/charting/action2d/Tooltip", ["dojo/_base/kernel", "dijit/Tooltip","dojo/_base/lang", "dojo/_base/html", "dojo/_base/declare", "./PlotAction", + "dojox/gfx/matrix", "dojox/lang/functional", "dojox/lang/functional/scan", "dojox/lang/functional/fold"], + function(dojo, Tooltip, lang, html, declare, PlotAction, m, df, dfs, dff){ + + /*===== + dojo.declare("dojox.charting.action2d.__TooltipCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for tooltip actions. + + // text: Function? + // The function that produces the text to be shown within a tooltip. By default this will be + // set by the plot in question, by returning the value of the element. + text: null + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_TEXT = function(o){ + var t = o.run && o.run.data && o.run.data[o.index]; + if(t && typeof t != "number" && (t.tooltip || t.text)){ + return t.tooltip || t.text; + } + if(o.element == "candlestick"){ + return '<table cellpadding="1" cellspacing="0" border="0" style="font-size:0.9em;">' + + '<tr><td>Open:</td><td align="right"><strong>' + o.data.open + '</strong></td></tr>' + + '<tr><td>High:</td><td align="right"><strong>' + o.data.high + '</strong></td></tr>' + + '<tr><td>Low:</td><td align="right"><strong>' + o.data.low + '</strong></td></tr>' + + '<tr><td>Close:</td><td align="right"><strong>' + o.data.close + '</strong></td></tr>' + + (o.data.mid !== undefined ? '<tr><td>Mid:</td><td align="right"><strong>' + o.data.mid + '</strong></td></tr>' : '') + + '</table>'; + } + return o.element == "bar" ? o.x : o.y; + }; + + var pi4 = Math.PI / 4, pi2 = Math.PI / 2; + + return declare("dojox.charting.action2d.Tooltip", PlotAction, { + // summary: + // Create an action on a plot where a tooltip is shown when hovering over an element. + + // the data description block for the widget parser + defaultParams: { + text: DEFAULT_TEXT // the function to produce a tooltip from the object + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the tooltip action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__TooltipCtorArgs? + // Optional keyword arguments object for setting parameters. + this.text = kwArgs && kwArgs.text ? kwArgs.text : DEFAULT_TEXT; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the highlighting action. + if(o.type === "onplotreset" || o.type === "onmouseout"){ + Tooltip.hide(this.aroundRect); + this.aroundRect = null; + if(o.type === "onplotreset"){ + delete this.angles; + } + return; + } + + if(!o.shape || o.type !== "onmouseover"){ return; } + + // calculate relative coordinates and the position + var aroundRect = {type: "rect"}, position = ["after", "before"]; + switch(o.element){ + case "marker": + aroundRect.x = o.cx; + aroundRect.y = o.cy; + aroundRect.w = aroundRect.h = 1; + break; + case "circle": + aroundRect.x = o.cx - o.cr; + aroundRect.y = o.cy - o.cr; + aroundRect.w = aroundRect.h = 2 * o.cr; + break; + case "column": + position = ["above", "below"]; + // intentional fall down + case "bar": + aroundRect = lang.clone(o.shape.getShape()); + aroundRect.w = aroundRect.width; + aroundRect.h = aroundRect.height; + break; + case "candlestick": + aroundRect.x = o.x; + aroundRect.y = o.y; + aroundRect.w = o.width; + aroundRect.h = o.height; + break; + default: + //case "slice": + if(!this.angles){ + // calculate the running total of slice angles + if(typeof o.run.data[0] == "number"){ + this.angles = df.map(df.scanl(o.run.data, "+", 0), + "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0)); + }else{ + this.angles = df.map(df.scanl(o.run.data, "a + b.y", 0), + "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0)); + } + } + var startAngle = m._degToRad(o.plot.opt.startAngle), + angle = (this.angles[o.index] + this.angles[o.index + 1]) / 2 + startAngle; + aroundRect.x = o.cx + o.cr * Math.cos(angle); + aroundRect.y = o.cy + o.cr * Math.sin(angle); + aroundRect.w = aroundRect.h = 1; + // calculate the position + if(angle < pi4){ + // do nothing: the position is right + }else if(angle < pi2 + pi4){ + position = ["below", "above"]; + }else if(angle < Math.PI + pi4){ + position = ["before", "after"]; + }else if(angle < 2 * Math.PI - pi4){ + position = ["above", "below"]; + } + /* + else{ + // do nothing: the position is right + } + */ + break; + } + + // adjust relative coordinates to absolute, and remove fractions + var lt = this.chart.getCoords(); + aroundRect.x += lt.x; + aroundRect.y += lt.y; + aroundRect.x = Math.round(aroundRect.x); + aroundRect.y = Math.round(aroundRect.y); + aroundRect.w = Math.ceil(aroundRect.w); + aroundRect.h = Math.ceil(aroundRect.h); + this.aroundRect = aroundRect; + + var tooltip = this.text(o); + if(this.chart.getTextDir){ + var isChartDirectionRtl = (html.style(this.chart.node,"direction") == "rtl"); + var isBaseTextDirRtl = (this.chart.getTextDir(tooltip) == "rtl"); + } + if(tooltip){ + if(isBaseTextDirRtl && !isChartDirectionRtl){ + Tooltip.show("<span dir = 'rtl'>" + tooltip +"</span>", this.aroundRect, position); + } + else if(!isBaseTextDirRtl && isChartDirectionRtl){ + Tooltip.show("<span dir = 'ltr'>" + tooltip +"</span>", this.aroundRect, position); + }else{ + Tooltip.show(tooltip, this.aroundRect, position); + } + } + } + }); +}); + +}, +'dojox/gfx':function(){ +define(["dojo/_base/lang", "./gfx/_base", "./gfx/renderer!"], + function(lang, gfxBase, renderer){ + // module: + // dojox/gfx + // summary: + // This the root of the Dojo Graphics package + gfxBase.switchTo(renderer); + return gfxBase; +}); + +}, +'dojox/gfx/shape':function(){ +define("dojox/gfx/shape", ["./_base", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/window", "dojo/_base/sniff", + "dojo/_base/connect", "dojo/_base/array", "dojo/dom-construct", "dojo/_base/Color", "./matrix"], + function(g, lang, declare, win, has, events, arr, domConstruct, Color, matrixLib){ + +/*===== + dojox.gfx.shape = { + // summary: + // This module contains the core graphics Shape API. + // Different graphics renderer implementation modules (svg, canvas, vml, silverlight, etc.) extend this + // basic api to provide renderer-specific implementations for each shape. + }; + =====*/ + + var shape = g.shape = {}; + // a set of ids (keys=type) + var _ids = {}; + // a simple set impl to map shape<->id + var registry = {}; + + shape.register = function(/*dojox.gfx.shape.Shape*/shape){ + // summary: + // Register the specified shape into the graphics registry. + // shape: dojox.gfx.shape.Shape + // The shape to register. + // returns: + // The unique id associated with this shape. + // the id pattern : type+number (ex: Rect0,Rect1,etc) + var t = shape.declaredClass.split('.').pop(); + var i = t in _ids ? ++_ids[t] : ((_ids[t] = 0)); + var uid = t+i; + registry[uid] = shape; + return uid; + }; + + shape.byId = function(/*String*/id){ + // summary: + // Returns the shape that matches the specified id. + // id: String + // The unique identifier for this Shape. + return registry[id]; //dojox.gfx.shape.Shape + }; + + shape.dispose = function(/*dojox.gfx.shape.Shape*/shape){ + // summary: + // Removes the specified shape from the registry. + // shape: dojox.gfx.shape.Shape + // The shape to unregister. + delete registry[shape.getUID()]; + }; + + declare("dojox.gfx.shape.Shape", null, { + // summary: a Shape object, which knows how to apply + // graphical attributes and transformations + + constructor: function(){ + // rawNode: Node + // underlying graphics-renderer-specific implementation object (if applicable) + this.rawNode = null; + // shape: Object: an abstract shape object + // (see dojox.gfx.defaultPath, + // dojox.gfx.defaultPolyline, + // dojox.gfx.defaultRect, + // dojox.gfx.defaultEllipse, + // dojox.gfx.defaultCircle, + // dojox.gfx.defaultLine, + // or dojox.gfx.defaultImage) + this.shape = null; + + // matrix: dojox.gfx.Matrix2D + // a transformation matrix + this.matrix = null; + + // fillStyle: Object + // a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + this.fillStyle = null; + + // strokeStyle: Object + // a stroke object + // (see dojox.gfx.defaultStroke) + this.strokeStyle = null; + + // bbox: dojox.gfx.Rectangle + // a bounding box of this shape + // (see dojox.gfx.defaultRect) + this.bbox = null; + + // virtual group structure + + // parent: Object + // a parent or null + // (see dojox.gfx.Surface, + // dojox.gfx.shape.VirtualGroup, + // or dojox.gfx.Group) + this.parent = null; + + // parentMatrix: dojox.gfx.Matrix2D + // a transformation matrix inherited from the parent + this.parentMatrix = null; + + var uid = shape.register(this); + this.getUID = function(){ + return uid; + } + }, + + // trivial getters + + getNode: function(){ + // summary: Different graphics rendering subsystems implement shapes in different ways. This + // method provides access to the underlying graphics subsystem object. Clients calling this + // method and using the return value must be careful not to try sharing or using the underlying node + // in a general way across renderer implementation. + // Returns the underlying graphics Node, or null if no underlying graphics node is used by this shape. + return this.rawNode; // Node + }, + getShape: function(){ + // summary: returns the current Shape object or null + // (see dojox.gfx.defaultPath, + // dojox.gfx.defaultPolyline, + // dojox.gfx.defaultRect, + // dojox.gfx.defaultEllipse, + // dojox.gfx.defaultCircle, + // dojox.gfx.defaultLine, + // or dojox.gfx.defaultImage) + return this.shape; // Object + }, + getTransform: function(){ + // summary: Returns the current transformation matrix applied to this Shape or null + return this.matrix; // dojox.gfx.Matrix2D + }, + getFill: function(){ + // summary: Returns the current fill object or null + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + return this.fillStyle; // Object + }, + getStroke: function(){ + // summary: Returns the current stroke object or null + // (see dojox.gfx.defaultStroke) + return this.strokeStyle; // Object + }, + getParent: function(){ + // summary: Returns the parent Shape, Group or VirtualGroup or null if this Shape is unparented. + // (see dojox.gfx.Surface, + // dojox.gfx.shape.VirtualGroup, + // or dojox.gfx.Group) + return this.parent; // Object + }, + getBoundingBox: function(){ + // summary: Returns the bounding box Rectanagle for this shape or null if a BoundingBox cannot be + // calculated for the shape on the current renderer or for shapes with no geometric area (points). + // A bounding box is a rectangular geometric region + // defining the X and Y extent of the shape. + // (see dojox.gfx.defaultRect) + return this.bbox; // dojox.gfx.Rectangle + }, + getTransformedBoundingBox: function(){ + // summary: returns an array of four points or null + // four points represent four corners of the untransformed bounding box + var b = this.getBoundingBox(); + if(!b){ + return null; // null + } + var m = this._getRealMatrix(), + gm = matrixLib; + return [ // Array + gm.multiplyPoint(m, b.x, b.y), + gm.multiplyPoint(m, b.x + b.width, b.y), + gm.multiplyPoint(m, b.x + b.width, b.y + b.height), + gm.multiplyPoint(m, b.x, b.y + b.height) + ]; + }, + getEventSource: function(){ + // summary: returns a Node, which is used as + // a source of events for this shape + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + return this.rawNode; // Node + }, + + // empty settings + + setShape: function(shape){ + // summary: sets a shape object + // (the default implementation simply ignores it) + // shape: Object + // a shape object + // (see dojox.gfx.defaultPath, + // dojox.gfx.defaultPolyline, + // dojox.gfx.defaultRect, + // dojox.gfx.defaultEllipse, + // dojox.gfx.defaultCircle, + // dojox.gfx.defaultLine, + // or dojox.gfx.defaultImage) + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + this.shape = g.makeParameters(this.shape, shape); + this.bbox = null; + return this; // self + }, + setFill: function(fill){ + // summary: sets a fill object + // (the default implementation simply ignores it) + // fill: Object + // a fill object + // (see dojox.gfx.defaultLinearGradient, + // dojox.gfx.defaultRadialGradient, + // dojox.gfx.defaultPattern, + // or dojo.Color) + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + if(!fill){ + // don't fill + this.fillStyle = null; + return this; // self + } + var f = null; + if(typeof(fill) == "object" && "type" in fill){ + // gradient or pattern + switch(fill.type){ + case "linear": + f = g.makeParameters(g.defaultLinearGradient, fill); + break; + case "radial": + f = g.makeParameters(g.defaultRadialGradient, fill); + break; + case "pattern": + f = g.makeParameters(g.defaultPattern, fill); + break; + } + }else{ + // color object + f = g.normalizeColor(fill); + } + this.fillStyle = f; + return this; // self + }, + setStroke: function(stroke){ + // summary: sets a stroke object + // (the default implementation simply ignores it) + // stroke: Object + // a stroke object + // (see dojox.gfx.defaultStroke) + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + if(!stroke){ + // don't stroke + this.strokeStyle = null; + return this; // self + } + // normalize the stroke + if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof Color){ + stroke = {color: stroke}; + } + var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke); + s.color = g.normalizeColor(s.color); + return this; // self + }, + setTransform: function(matrix){ + // summary: sets a transformation matrix + // matrix: dojox.gfx.Matrix2D + // a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + this.matrix = matrixLib.clone(matrix ? matrixLib.normalize(matrix) : matrixLib.identity); + return this._applyTransform(); // self + }, + + _applyTransform: function(){ + // summary: physically sets a matrix + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + return this; // self + }, + + // z-index + + moveToFront: function(){ + // summary: moves a shape to front of its parent's list of shapes + var p = this.getParent(); + if(p){ + p._moveChildToFront(this); + this._moveToFront(); // execute renderer-specific action + } + return this; // self + }, + moveToBack: function(){ + // summary: moves a shape to back of its parent's list of shapes + var p = this.getParent(); + if(p){ + p._moveChildToBack(this); + this._moveToBack(); // execute renderer-specific action + } + return this; + }, + _moveToFront: function(){ + // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront() + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + }, + _moveToBack: function(){ + // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront() + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + }, + + // apply left & right transformation + + applyRightTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on right side + // (this.matrix * matrix) + // matrix: dojox.gfx.Matrix2D + // a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([this.matrix, matrix]) : this; // self + }, + applyLeftTransform: function(matrix){ + // summary: multiplies the existing matrix with an argument on left side + // (matrix * this.matrix) + // matrix: dojox.gfx.Matrix2D + // a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([matrix, this.matrix]) : this; // self + }, + applyTransform: function(matrix){ + // summary: a shortcut for dojox.gfx.Shape.applyRightTransform + // matrix: dojox.gfx.Matrix2D + // a matrix or a matrix-like object + // (see an argument of dojox.gfx.Matrix2D + // constructor for a list of acceptable arguments) + return matrix ? this.setTransform([this.matrix, matrix]) : this; // self + }, + + // virtual group methods + + removeShape: function(silently){ + // summary: removes the shape from its parent's list of shapes + // silently: Boolean + // if true, do not redraw a picture yet + if(this.parent){ + this.parent.remove(this, silently); + } + return this; // self + }, + _setParent: function(parent, matrix){ + // summary: sets a parent + // parent: Object + // a parent or null + // (see dojox.gfx.Surface, + // dojox.gfx.shape.VirtualGroup, + // or dojox.gfx.Group) + // matrix: dojox.gfx.Matrix2D + // a 2D matrix or a matrix-like object + this.parent = parent; + return this._updateParentMatrix(matrix); // self + }, + _updateParentMatrix: function(matrix){ + // summary: updates the parent matrix with new matrix + // matrix: dojox.gfx.Matrix2D + // a 2D matrix or a matrix-like object + this.parentMatrix = matrix ? matrixLib.clone(matrix) : null; + return this._applyTransform(); // self + }, + _getRealMatrix: function(){ + // summary: returns the cumulative ('real') transformation matrix + // by combining the shape's matrix with its parent's matrix + var m = this.matrix; + var p = this.parent; + while(p){ + if(p.matrix){ + m = matrixLib.multiply(p.matrix, m); + } + p = p.parent; + } + return m; // dojox.gfx.Matrix2D + } + }); + + shape._eventsProcessing = { + connect: function(name, object, method){ + // summary: connects a handler to an event on this shape + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + // redirect to fixCallback to normalize events and add the gfxTarget to the event. The latter + // is done by dojox.gfx.fixTarget which is defined by each renderer + return events.connect(this.getEventSource(), name, shape.fixCallback(this, g.fixTarget, object, method)); + + }, + disconnect: function(token){ + // summary: connects a handler by token from an event on this shape + // COULD BE RE-IMPLEMENTED BY THE RENDERER! + + events.disconnect(token); + } + }; + + shape.fixCallback = function(gfxElement, fixFunction, scope, method){ + // summary: + // Wraps the callback to allow for tests and event normalization + // before it gets invoked. This is where 'fixTarget' is invoked. + // gfxElement: Object + // The GFX object that triggers the action (ex.: + // dojox.gfx.Surface and dojox.gfx.Shape). A new event property + // 'gfxTarget' is added to the event to reference this object. + // for easy manipulation of GFX objects by the event handlers. + // fixFunction: Function + // The function that implements the logic to set the 'gfxTarget' + // property to the event. It should be 'dojox.gfx.fixTarget' for + // most of the cases + // scope: Object + // Optional. The scope to be used when invoking 'method'. If + // omitted, a global scope is used. + // method: Function|String + // The original callback to be invoked. + if(!method){ + method = scope; + scope = null; + } + if(lang.isString(method)){ + scope = scope || win.global; + if(!scope[method]){ throw(['dojox.gfx.shape.fixCallback: scope["', method, '"] is null (scope="', scope, '")'].join('')); } + return function(e){ + return fixFunction(e,gfxElement) ? scope[method].apply(scope, arguments || []) : undefined; }; // Function + } + return !scope + ? function(e){ + return fixFunction(e,gfxElement) ? method.apply(scope, arguments) : undefined; } + : function(e){ + return fixFunction(e,gfxElement) ? method.apply(scope, arguments || []) : undefined; }; // Function + }; + lang.extend(shape.Shape, shape._eventsProcessing); + + shape.Container = { + // summary: a container of shapes, which can be used + // as a foundation for renderer-specific groups, or as a way + // to logically group shapes (e.g, to propagate matricies) + + _init: function() { + // children: Array: a list of children + this.children = []; + }, + + // group management + + openBatch: function() { + // summary: starts a new batch, subsequent new child shapes will be held in + // the batch instead of appending to the container directly + }, + closeBatch: function() { + // summary: submits the current batch, append all pending child shapes to DOM + }, + add: function(shape){ + // summary: adds a shape to the list + // shape: dojox.gfx.Shape + // the shape to add to the list + var oldParent = shape.getParent(); + if(oldParent){ + oldParent.remove(shape, true); + } + this.children.push(shape); + return shape._setParent(this, this._getRealMatrix()); // self + }, + remove: function(shape, silently){ + // summary: removes a shape from the list + // shape: dojox.gfx.shape.Shape + // the shape to remove + // silently: Boolean + // if true, do not redraw a picture yet + for(var i = 0; i < this.children.length; ++i){ + if(this.children[i] == shape){ + if(silently){ + // skip for now + }else{ + shape.parent = null; + shape.parentMatrix = null; + } + this.children.splice(i, 1); + break; + } + } + return this; // self + }, + clear: function(){ + // summary: removes all shapes from a group/surface + var shape; + for(var i = 0; i < this.children.length;++i){ + shape = this.children[i]; + shape.parent = null; + shape.parentMatrix = null; + } + this.children = []; + return this; // self + }, + + // moving child nodes + + _moveChildToFront: function(shape){ + // summary: moves a shape to front of the list of shapes + // shape: dojox.gfx.shape.Shape + // one of the child shapes to move to the front + for(var i = 0; i < this.children.length; ++i){ + if(this.children[i] == shape){ + this.children.splice(i, 1); + this.children.push(shape); + break; + } + } + return this; // self + }, + _moveChildToBack: function(shape){ + // summary: moves a shape to back of the list of shapes + // shape: dojox.gfx.shape.Shape + // one of the child shapes to move to the front + for(var i = 0; i < this.children.length; ++i){ + if(this.children[i] == shape){ + this.children.splice(i, 1); + this.children.unshift(shape); + break; + } + } + return this; // self + } + }; + + declare("dojox.gfx.shape.Surface", null, { + // summary: a surface object to be used for drawings + constructor: function(){ + // underlying node + this.rawNode = null; + // the parent node + this._parent = null; + // the list of DOM nodes to be deleted in the case of destruction + this._nodes = []; + // the list of events to be detached in the case of destruction + this._events = []; + }, + destroy: function(){ + // summary: destroy all relevant external resources and release all + // external references to make this object garbage-collectible + arr.forEach(this._nodes, domConstruct.destroy); + this._nodes = []; + arr.forEach(this._events, events.disconnect); + this._events = []; + this.rawNode = null; // recycle it in _nodes, if it needs to be recycled + if(has("ie")){ + while(this._parent.lastChild){ + domConstruct.destroy(this._parent.lastChild); + } + }else{ + this._parent.innerHTML = ""; + } + this._parent = null; + }, + getEventSource: function(){ + // summary: returns a node, which can be used to attach event listeners + return this.rawNode; // Node + }, + _getRealMatrix: function(){ + // summary: always returns the identity matrix + return null; // dojox.gfx.Matrix2D + }, + isLoaded: true, + onLoad: function(/*dojox.gfx.Surface*/ surface){ + // summary: local event, fired once when the surface is created + // asynchronously, used only when isLoaded is false, required + // only for Silverlight. + }, + whenLoaded: function(/*Object|Null*/ context, /*Function|String*/ method){ + var f = lang.hitch(context, method); + if(this.isLoaded){ + f(this); + }else{ + var h = events.connect(this, "onLoad", function(surface){ + events.disconnect(h); + f(surface); + }); + } + } + }); + + lang.extend(shape.Surface, shape._eventsProcessing); + + declare("dojox.gfx.Point", null, { + // summary: a hypothetical 2D point to be used for drawings - {x, y} + // description: This object is defined for documentation purposes. + // You should use the naked object instead: {x: 1, y: 2}. + }); + + declare("dojox.gfx.Rectangle", null, { + // summary: a hypothetical rectangle - {x, y, width, height} + // description: This object is defined for documentation purposes. + // You should use the naked object instead: {x: 1, y: 2, width: 100, height: 200}. + }); + + declare("dojox.gfx.shape.Rect", shape.Shape, { + // summary: a generic rectangle + constructor: function(rawNode){ + // rawNode: Node + // The underlying graphics system object (typically a DOM Node) + this.shape = g.getDefault("Rect"); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box (its shape in this case) + return this.shape; // dojox.gfx.Rectangle + } + }); + + declare("dojox.gfx.shape.Ellipse", shape.Shape, { + // summary: a generic ellipse + constructor: function(rawNode){ + // rawNode: Node + // a DOM Node + this.shape = g.getDefault("Ellipse"); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox){ + var shape = this.shape; + this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry, + width: 2 * shape.rx, height: 2 * shape.ry}; + } + return this.bbox; // dojox.gfx.Rectangle + } + }); + + declare("dojox.gfx.shape.Circle", shape.Shape, { + // summary: a generic circle + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode){ + // rawNode: Node + // a DOM Node + this.shape = g.getDefault("Circle"); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox){ + var shape = this.shape; + this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r, + width: 2 * shape.r, height: 2 * shape.r}; + } + return this.bbox; // dojox.gfx.Rectangle + } + }); + + declare("dojox.gfx.shape.Line", shape.Shape, { + // summary: a generic line + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode){ + // rawNode: Node + // a DOM Node + this.shape = g.getDefault("Line"); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox){ + var shape = this.shape; + this.bbox = { + x: Math.min(shape.x1, shape.x2), + y: Math.min(shape.y1, shape.y2), + width: Math.abs(shape.x2 - shape.x1), + height: Math.abs(shape.y2 - shape.y1) + }; + } + return this.bbox; // dojox.gfx.Rectangle + } + }); + + declare("dojox.gfx.shape.Polyline", shape.Shape, { + // summary: a generic polyline/polygon + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode){ + // rawNode: Node + // a DOM Node + this.shape = g.getDefault("Polyline"); + this.rawNode = rawNode; + }, + setShape: function(points, closed){ + // summary: sets a polyline/polygon shape object + // points: Object + // a polyline/polygon shape object + // closed: Boolean + // close the polyline to make a polygon + if(points && points instanceof Array){ + // points: Array: an array of points + this.inherited(arguments, [{points: points}]); + if(closed && this.shape.points.length){ + this.shape.points.push(this.shape.points[0]); + } + }else{ + this.inherited(arguments, [points]); + } + return this; // self + }, + _normalizePoints: function(){ + // summary: normalize points to array of {x:number, y:number} + var p = this.shape.points, l = p && p.length; + if(l && typeof p[0] == "number"){ + var points = []; + for(var i = 0; i < l; i += 2){ + points.push({x: p[i], y: p[i + 1]}); + } + this.shape.points = points; + } + }, + getBoundingBox: function(){ + // summary: returns the bounding box + if(!this.bbox && this.shape.points.length){ + var p = this.shape.points; + var l = p.length; + var t = p[0]; + var bbox = {l: t.x, t: t.y, r: t.x, b: t.y}; + for(var i = 1; i < l; ++i){ + t = p[i]; + if(bbox.l > t.x) bbox.l = t.x; + if(bbox.r < t.x) bbox.r = t.x; + if(bbox.t > t.y) bbox.t = t.y; + if(bbox.b < t.y) bbox.b = t.y; + } + this.bbox = { + x: bbox.l, + y: bbox.t, + width: bbox.r - bbox.l, + height: bbox.b - bbox.t + }; + } + return this.bbox; // dojox.gfx.Rectangle + } + }); + + declare("dojox.gfx.shape.Image", shape.Shape, { + // summary: a generic image + // (this is a helper object, which is defined for convenience) + constructor: function(rawNode){ + // rawNode: Node + // a DOM Node + this.shape = g.getDefault("Image"); + this.rawNode = rawNode; + }, + getBoundingBox: function(){ + // summary: returns the bounding box (its shape in this case) + return this.shape; // dojox.gfx.Rectangle + }, + setStroke: function(){ + // summary: ignore setting a stroke style + return this; // self + }, + setFill: function(){ + // summary: ignore setting a fill style + return this; // self + } + }); + + declare("dojox.gfx.shape.Text", shape.Shape, { + // summary: a generic text + constructor: function(rawNode){ + // rawNode: Node + // a DOM Node + this.fontStyle = null; + this.shape = g.getDefault("Text"); + this.rawNode = rawNode; + }, + getFont: function(){ + // summary: returns the current font object or null + return this.fontStyle; // Object + }, + setFont: function(newFont){ + // summary: sets a font for text + // newFont: Object + // a font object (see dojox.gfx.defaultFont) or a font string + this.fontStyle = typeof newFont == "string" ? g.splitFontString(newFont) : + g.makeParameters(g.defaultFont, newFont); + this._setFont(); + return this; // self + } + }); + + shape.Creator = { + // summary: shape creators + createShape: function(shape){ + // summary: creates a shape object based on its type; it is meant to be used + // by group-like objects + // shape: Object + // a shape descriptor object + switch(shape.type){ + case g.defaultPath.type: return this.createPath(shape); + case g.defaultRect.type: return this.createRect(shape); + case g.defaultCircle.type: return this.createCircle(shape); + case g.defaultEllipse.type: return this.createEllipse(shape); + case g.defaultLine.type: return this.createLine(shape); + case g.defaultPolyline.type: return this.createPolyline(shape); + case g.defaultImage.type: return this.createImage(shape); + case g.defaultText.type: return this.createText(shape); + case g.defaultTextPath.type: return this.createTextPath(shape); + } + return null; + }, + createGroup: function(){ + // summary: creates a group shape + return this.createObject(g.Group); // dojox.gfx.Group + }, + createRect: function(rect){ + // summary: creates a rectangle shape + // rect: Object + // a path object (see dojox.gfx.defaultRect) + return this.createObject(g.Rect, rect); // dojox.gfx.Rect + }, + createEllipse: function(ellipse){ + // summary: creates an ellipse shape + // ellipse: Object + // an ellipse object (see dojox.gfx.defaultEllipse) + return this.createObject(g.Ellipse, ellipse); // dojox.gfx.Ellipse + }, + createCircle: function(circle){ + // summary: creates a circle shape + // circle: Object + // a circle object (see dojox.gfx.defaultCircle) + return this.createObject(g.Circle, circle); // dojox.gfx.Circle + }, + createLine: function(line){ + // summary: creates a line shape + // line: Object + // a line object (see dojox.gfx.defaultLine) + return this.createObject(g.Line, line); // dojox.gfx.Line + }, + createPolyline: function(points){ + // summary: creates a polyline/polygon shape + // points: Object + // a points object (see dojox.gfx.defaultPolyline) + // or an Array of points + return this.createObject(g.Polyline, points); // dojox.gfx.Polyline + }, + createImage: function(image){ + // summary: creates a image shape + // image: Object + // an image object (see dojox.gfx.defaultImage) + return this.createObject(g.Image, image); // dojox.gfx.Image + }, + createText: function(text){ + // summary: creates a text shape + // text: Object + // a text object (see dojox.gfx.defaultText) + return this.createObject(g.Text, text); // dojox.gfx.Text + }, + createPath: function(path){ + // summary: creates a path shape + // path: Object + // a path object (see dojox.gfx.defaultPath) + return this.createObject(g.Path, path); // dojox.gfx.Path + }, + createTextPath: function(text){ + // summary: creates a text shape + // text: Object + // a textpath object (see dojox.gfx.defaultTextPath) + return this.createObject(g.TextPath, {}).setText(text); // dojox.gfx.TextPath + }, + createObject: function(shapeType, rawShape){ + // summary: creates an instance of the passed shapeType class + // SHOULD BE RE-IMPLEMENTED BY THE RENDERER! + // shapeType: Function + // a class constructor to create an instance of + // rawShape: Object + // properties to be passed in to the classes 'setShape' method + + return null; // dojox.gfx.Shape + } + }; + + return shape; +}); + + +}, +'dojox/charting/Chart2D':function(){ +define("dojox/charting/Chart2D", ["dojo/_base/kernel", "dojox", "./Chart", + "./axis2d/Default", "./axis2d/Invisible", "./plot2d/Default", "./plot2d/Lines", "./plot2d/Areas", + "./plot2d/Markers", "./plot2d/MarkersOnly", "./plot2d/Scatter", "./plot2d/Stacked", "./plot2d/StackedLines", + "./plot2d/StackedAreas", "./plot2d/Columns", "./plot2d/StackedColumns", "./plot2d/ClusteredColumns", + "./plot2d/Bars", "./plot2d/StackedBars", "./plot2d/ClusteredBars", "./plot2d/Grid", "./plot2d/Pie", + "./plot2d/Bubble", "./plot2d/Candlesticks", "./plot2d/OHLC", "./plot2d/Spider"], + function(dojo, dojox, Chart){ + dojo.deprecated("dojox.charting.Chart2D", "Use dojo.charting.Chart instead and require all other components explicitly", "2.0"); + // module: + // dojox/charting/Chart2D + // summary: + // This is a compatibility module which loads all charting modules that used to be automatically + // loaded in versions prior to 1.6. It is highly recommended for performance reasons that + // this module no longer be referenced by applications. Instead, use dojox/charting/Chart. + return dojox.charting.Chart2D = Chart; +}); + +}, +'dojox/charting/scaler/linear':function(){ +define("dojox/charting/scaler/linear", ["dojo/_base/lang", "./common"], + function(lang, common){ + var linear = lang.getObject("dojox.charting.scaler.linear", true); + + var deltaLimit = 3, // pixels + findString = common.findString, + getLabel = common.getNumericLabel; + + var calcTicks = function(min, max, kwArgs, majorTick, minorTick, microTick, span){ + kwArgs = lang.delegate(kwArgs); + if(!majorTick){ + if(kwArgs.fixUpper == "major"){ kwArgs.fixUpper = "minor"; } + if(kwArgs.fixLower == "major"){ kwArgs.fixLower = "minor"; } + } + if(!minorTick){ + if(kwArgs.fixUpper == "minor"){ kwArgs.fixUpper = "micro"; } + if(kwArgs.fixLower == "minor"){ kwArgs.fixLower = "micro"; } + } + if(!microTick){ + if(kwArgs.fixUpper == "micro"){ kwArgs.fixUpper = "none"; } + if(kwArgs.fixLower == "micro"){ kwArgs.fixLower = "none"; } + } + var lowerBound = findString(kwArgs.fixLower, ["major"]) ? + Math.floor(kwArgs.min / majorTick) * majorTick : + findString(kwArgs.fixLower, ["minor"]) ? + Math.floor(kwArgs.min / minorTick) * minorTick : + findString(kwArgs.fixLower, ["micro"]) ? + Math.floor(kwArgs.min / microTick) * microTick : kwArgs.min, + upperBound = findString(kwArgs.fixUpper, ["major"]) ? + Math.ceil(kwArgs.max / majorTick) * majorTick : + findString(kwArgs.fixUpper, ["minor"]) ? + Math.ceil(kwArgs.max / minorTick) * minorTick : + findString(kwArgs.fixUpper, ["micro"]) ? + Math.ceil(kwArgs.max / microTick) * microTick : kwArgs.max; + + if(kwArgs.useMin){ min = lowerBound; } + if(kwArgs.useMax){ max = upperBound; } + + var majorStart = (!majorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major"])) ? + min : Math.ceil(min / majorTick) * majorTick, + minorStart = (!minorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor"])) ? + min : Math.ceil(min / minorTick) * minorTick, + microStart = (! microTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor", "micro"])) ? + min : Math.ceil(min / microTick) * microTick, + majorCount = !majorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major"]) ? + Math.round((max - majorStart) / majorTick) : + Math.floor((max - majorStart) / majorTick)) + 1, + minorCount = !minorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor"]) ? + Math.round((max - minorStart) / minorTick) : + Math.floor((max - minorStart) / minorTick)) + 1, + microCount = !microTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor", "micro"]) ? + Math.round((max - microStart) / microTick) : + Math.floor((max - microStart) / microTick)) + 1, + minorPerMajor = minorTick ? Math.round(majorTick / minorTick) : 0, + microPerMinor = microTick ? Math.round(minorTick / microTick) : 0, + majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0, + minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0, + scale = span / (max - min); + if(!isFinite(scale)){ scale = 1; } + + return { + bounds: { + lower: lowerBound, + upper: upperBound, + from: min, + to: max, + scale: scale, + span: span + }, + major: { + tick: majorTick, + start: majorStart, + count: majorCount, + prec: majorPrecision + }, + minor: { + tick: minorTick, + start: minorStart, + count: minorCount, + prec: minorPrecision + }, + micro: { + tick: microTick, + start: microStart, + count: microCount, + prec: 0 + }, + minorPerMajor: minorPerMajor, + microPerMinor: microPerMinor, + scaler: linear + }; + }; + + return lang.mixin(linear, { + buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){ + var h = {fixUpper: "none", fixLower: "none", natural: false}; + if(kwArgs){ + if("fixUpper" in kwArgs){ h.fixUpper = String(kwArgs.fixUpper); } + if("fixLower" in kwArgs){ h.fixLower = String(kwArgs.fixLower); } + if("natural" in kwArgs){ h.natural = Boolean(kwArgs.natural); } + } + + // update bounds + if("min" in kwArgs){ min = kwArgs.min; } + if("max" in kwArgs){ max = kwArgs.max; } + if(kwArgs.includeZero){ + if(min > 0){ min = 0; } + if(max < 0){ max = 0; } + } + h.min = min; + h.useMin = true; + h.max = max; + h.useMax = true; + + if("from" in kwArgs){ + min = kwArgs.from; + h.useMin = false; + } + if("to" in kwArgs){ + max = kwArgs.to; + h.useMax = false; + } + + // check for erroneous condition + if(max <= min){ + return calcTicks(min, max, h, 0, 0, 0, span); // Object + } + + var mag = Math.floor(Math.log(max - min) / Math.LN10), + major = kwArgs && ("majorTickStep" in kwArgs) ? kwArgs.majorTickStep : Math.pow(10, mag), + minor = 0, micro = 0, ticks; + + // calculate minor ticks + if(kwArgs && ("minorTickStep" in kwArgs)){ + minor = kwArgs.minorTickStep; + }else{ + do{ + minor = major / 10; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } + } + minor = major / 5; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } + } + minor = major / 2; + if(!h.natural || minor > 0.9){ + ticks = calcTicks(min, max, h, major, minor, 0, span); + if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } + } + return calcTicks(min, max, h, major, 0, 0, span); // Object + }while(false); + } + + // calculate micro ticks + if(kwArgs && ("microTickStep" in kwArgs)){ + micro = kwArgs.microTickStep; + ticks = calcTicks(min, max, h, major, minor, micro, span); + }else{ + do{ + micro = minor / 10; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = minor / 5; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = minor / 2; + if(!h.natural || micro > 0.9){ + ticks = calcTicks(min, max, h, major, minor, micro, span); + if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } + } + micro = 0; + }while(false); + } + + return micro ? ticks : calcTicks(min, max, h, major, minor, 0, span); // Object + }, + buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){ + var step, next, tick, + nextMajor = scaler.major.start, + nextMinor = scaler.minor.start, + nextMicro = scaler.micro.start; + if(kwArgs.microTicks && scaler.micro.tick){ + step = scaler.micro.tick, next = nextMicro; + }else if(kwArgs.minorTicks && scaler.minor.tick){ + step = scaler.minor.tick, next = nextMinor; + }else if(scaler.major.tick){ + step = scaler.major.tick, next = nextMajor; + }else{ + // no ticks + return null; + } + // make sure that we have finite bounds + var revScale = 1 / scaler.bounds.scale; + if(scaler.bounds.to <= scaler.bounds.from || isNaN(revScale) || !isFinite(revScale) || + step <= 0 || isNaN(step) || !isFinite(step)){ + // no ticks + return null; + } + // loop over all ticks + var majorTicks = [], minorTicks = [], microTicks = []; + while(next <= scaler.bounds.to + revScale){ + if(Math.abs(nextMajor - next) < step / 2){ + // major tick + tick = {value: nextMajor}; + if(kwArgs.majorLabels){ + tick.label = getLabel(nextMajor, scaler.major.prec, kwArgs); + } + majorTicks.push(tick); + nextMajor += scaler.major.tick; + nextMinor += scaler.minor.tick; + nextMicro += scaler.micro.tick; + }else if(Math.abs(nextMinor - next) < step / 2){ + // minor tick + if(kwArgs.minorTicks){ + tick = {value: nextMinor}; + if(kwArgs.minorLabels && (scaler.minMinorStep <= scaler.minor.tick * scaler.bounds.scale)){ + tick.label = getLabel(nextMinor, scaler.minor.prec, kwArgs); + } + minorTicks.push(tick); + } + nextMinor += scaler.minor.tick; + nextMicro += scaler.micro.tick; + }else{ + // micro tick + if(kwArgs.microTicks){ + microTicks.push({value: nextMicro}); + } + nextMicro += scaler.micro.tick; + } + next += step; + } + return {major: majorTicks, minor: minorTicks, micro: microTicks}; // Object + }, + getTransformerFromModel: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return (x - offset) * scale; }; // Function + }, + getTransformerFromPlot: function(/*Object*/ scaler){ + var offset = scaler.bounds.from, scale = scaler.bounds.scale; + return function(x){ return x / scale + offset; }; // Function + } + }); +}); + +}, +'dojox/gfx/renderer':function(){ +define("dojox/gfx/renderer", ["./_base","dojo/_base/lang", "dojo/_base/sniff", "dojo/_base/window", "dojo/_base/config"], + function(g, lang, has, win, config){ + //>> noBuildResolver +/*===== + dojox.gfx.renderer = { + // summary: + // This module is an AMD loader plugin that loads the appropriate graphics renderer + // implementation based on detected environment and current configuration settings. + }; + =====*/ + var currentRenderer = null; + return { + load: function(id, require, load){ + if(currentRenderer && id != "force"){ + load(currentRenderer); + return; + } + var renderer = config.forceGfxRenderer, + renderers = !renderer && (lang.isString(config.gfxRenderer) ? + config.gfxRenderer : "svg,vml,canvas,silverlight").split(","), + silverlightObject, silverlightFlag; + + while(!renderer && renderers.length){ + switch(renderers.shift()){ + case "svg": + // the next test is from https://github.com/phiggins42/has.js + if("SVGAngle" in win.global){ + renderer = "svg"; + } + break; + case "vml": + if(has("ie")){ + renderer = "vml"; + } + break; + case "silverlight": + try{ + if(has("ie")){ + silverlightObject = new ActiveXObject("AgControl.AgControl"); + if(silverlightObject && silverlightObject.IsVersionSupported("1.0")){ + silverlightFlag = true; + } + }else{ + if(navigator.plugins["Silverlight Plug-In"]){ + silverlightFlag = true; + } + } + }catch(e){ + silverlightFlag = false; + }finally{ + silverlightObject = null; + } + if(silverlightFlag){ + renderer = "silverlight"; + } + break; + case "canvas": + if(win.global.CanvasRenderingContext2D){ + renderer = "canvas"; + } + break; + } + } + + if (renderer === 'canvas' && config.canvasEvents !== false) { + renderer = "canvasWithEvents"; + } + + if(config.isDebug){ + console.log("gfx renderer = " + renderer); + } + + function loadRenderer(){ + require(["dojox/gfx/" + renderer], function(module){ + g.renderer = renderer; + // memorize the renderer module + currentRenderer = module; + // now load it + load(module); + }); + } + if(renderer == "svg" && typeof window.svgweb != "undefined"){ + window.svgweb.addOnLoad(loadRenderer); + }else{ + loadRenderer(); + } + } + }; +}); + +}, +'dojox/charting/widget/Chart':function(){ +define("dojox/charting/widget/Chart", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array","dojo/_base/html","dojo/_base/declare", "dojo/query", + "dijit/_Widget", "../Chart", "dojox/lang/utils", "dojox/lang/functional","dojox/lang/functional/lambda", + "dijit/_base/manager"], + function(kernel, lang, arr, html, declare, query, Widget, Chart, du, df, dfl){ +/*===== +var Widget = dijit._Widget; +=====*/ + var collectParams, collectAxisParams, collectPlotParams, + collectActionParams, collectDataParams, + notNull = function(o){ return o; }, + dc = lang.getObject("dojox.charting"); + + var ChartWidget = declare("dojox.charting.widget.Chart", Widget, { + // parameters for the markup + + // theme for the chart + theme: null, + + // margins for the chart: {l: 10, r: 10, t: 10, b: 10} + margins: null, + + // chart area, define them as undefined to: + // allow the parser to take them into account + // but make sure they have no defined value to not override theme + stroke: undefined, + fill: undefined, + + // methods + + buildRendering: function(){ + this.inherited(arguments); + + n = this.domNode; + + // collect chart parameters + var axes = query("> .axis", n).map(collectAxisParams).filter(notNull), + plots = query("> .plot", n).map(collectPlotParams).filter(notNull), + actions = query("> .action", n).map(collectActionParams).filter(notNull), + series = query("> .series", n).map(collectDataParams).filter(notNull); + + // build the chart + n.innerHTML = ""; + var c = this.chart = new Chart(n, { + margins: this.margins, + stroke: this.stroke, + fill: this.fill, + textDir: this.textDir + }); + + // add collected parameters + if(this.theme){ + c.setTheme(this.theme); + } + axes.forEach(function(axis){ + c.addAxis(axis.name, axis.kwArgs); + }); + plots.forEach(function(plot){ + c.addPlot(plot.name, plot.kwArgs); + }); + + this.actions = actions.map(function(action){ + return new action.action(c, action.plot, action.kwArgs); + }); + + var render = df.foldl(series, function(render, series){ + if(series.type == "data"){ + c.addSeries(series.name, series.data, series.kwArgs); + render = true; + }else{ + c.addSeries(series.name, [0], series.kwArgs); + var kw = {}; + du.updateWithPattern( + kw, + series.kwArgs, + { + "query": "", + "queryOptions": null, + "start": 0, + "count": 1 //, + // "sort": [] + }, + true + ); + if(series.kwArgs.sort){ + // sort is a complex object type and doesn't survive coercian + kw.sort = lang.clone(series.kwArgs.sort); + } + lang.mixin(kw, { + onComplete: function(data){ + var values; + if("valueFn" in series.kwArgs){ + var fn = series.kwArgs.valueFn; + values = arr.map(data, function(x){ + return fn(series.data.getValue(x, series.field, 0)); + }); + }else{ + values = arr.map(data, function(x){ + return series.data.getValue(x, series.field, 0); + }); + } + c.addSeries(series.name, values, series.kwArgs).render(); + } + }); + series.data.fetch(kw); + } + return render; + }, false); + if(render){ c.render(); } + }, + destroy: function(){ + // summary: properly destroy the widget + this.chart.destroy(); + this.inherited(arguments); + }, + resize: function(box){ + // summary: + // Resize the widget. + // description: + // Resize the domNode and the widget surface to the dimensions of a box of the following form: + // `{ l: 50, t: 200, w: 300: h: 150 }` + // If no box is provided, resize the surface to the marginBox of the domNode. + // box: + // If passed, denotes the new size of the widget. + this.chart.resize(box); + } + }); + + collectParams = function(node, type, kw){ + var dp = eval("(" + type + ".prototype.defaultParams)"); + var x, attr; + for(x in dp){ + if(x in kw){ continue; } + attr = node.getAttribute(x); + kw[x] = du.coerceType(dp[x], attr == null || typeof attr == "undefined" ? dp[x] : attr); + } + var op = eval("(" + type + ".prototype.optionalParams)"); + for(x in op){ + if(x in kw){ continue; } + attr = node.getAttribute(x); + if(attr != null){ + kw[x] = du.coerceType(op[x], attr); + } + } + }; + + collectAxisParams = function(node){ + var name = node.getAttribute("name"), type = node.getAttribute("type"); + if(!name){ return null; } + var o = {name: name, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dc.axis2d[type]){ + type = dojo._scopeName + "x.charting.axis2d." + type; + } + var axis = eval("(" + type + ")"); + if(axis){ kw.type = axis; } + }else{ + type = dojo._scopeName + "x.charting.axis2d.Default"; + } + collectParams(node, type, kw); + // compatibility conversions + if(kw.font || kw.fontColor){ + if(!kw.tick){ + kw.tick = {}; + } + if(kw.font){ + kw.tick.font = kw.font; + } + if(kw.fontColor){ + kw.tick.fontColor = kw.fontColor; + } + } + return o; + }; + + collectPlotParams = function(node){ + // var name = d.attr(node, "name"), type = d.attr(node, "type"); + var name = node.getAttribute("name"), type = node.getAttribute("type"); + if(!name){ return null; } + var o = {name: name, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dc.plot2d && dc.plot2d[type]){ + type = dojo._scopeName + "x.charting.plot2d." + type; + } + var plot = eval("(" + type + ")"); + if(plot){ kw.type = plot; } + }else{ + type = dojo._scopeName + "x.charting.plot2d.Default"; + } + collectParams(node, type, kw); + return o; + }; + + collectActionParams = function(node){ + // var plot = d.attr(node, "plot"), type = d.attr(node, "type"); + var plot = node.getAttribute("plot"), type = node.getAttribute("type"); + if(!plot){ plot = "default"; } + var o = {plot: plot, kwArgs: {}}, kw = o.kwArgs; + if(type){ + if(dc.action2d[type]){ + type = dojo._scopeName + "x.charting.action2d." + type; + } + var action = eval("(" + type + ")"); + if(!action){ return null; } + o.action = action; + }else{ + return null; + } + collectParams(node, type, kw); + return o; + }; + + collectDataParams = function(node){ + var ga = lang.partial(html.attr, node); + var name = ga("name"); + if(!name){ return null; } + var o = { name: name, kwArgs: {} }, kw = o.kwArgs, t; + t = ga("plot"); + if(t != null){ kw.plot = t; } + t = ga("marker"); + if(t != null){ kw.marker = t; } + t = ga("stroke"); + if(t != null){ kw.stroke = eval("(" + t + ")"); } + t = ga("outline"); + if(t != null){ kw.outline = eval("(" + t + ")"); } + t = ga("shadow"); + if(t != null){ kw.shadow = eval("(" + t + ")"); } + t = ga("fill"); + if(t != null){ kw.fill = eval("(" + t + ")"); } + t = ga("font"); + if(t != null){ kw.font = t; } + t = ga("fontColor"); + if(t != null){ kw.fontColor = eval("(" + t + ")"); } + t = ga("legend"); + if(t != null){ kw.legend = t; } + t = ga("data"); + if(t != null){ + o.type = "data"; + o.data = t ? arr.map(String(t).split(','), Number) : []; + return o; + } + t = ga("array"); + if(t != null){ + o.type = "data"; + o.data = eval("(" + t + ")"); + return o; + } + t = ga("store"); + if(t != null){ + o.type = "store"; + o.data = eval("(" + t + ")"); + t = ga("field"); + o.field = t != null ? t : "value"; + t = ga("query"); + if(!!t){ kw.query = t; } + t = ga("queryOptions"); + if(!!t){ kw.queryOptions = eval("(" + t + ")"); } + t = ga("start"); + if(!!t){ kw.start = Number(t); } + t = ga("count"); + if(!!t){ kw.count = Number(t); } + t = ga("sort"); + if(!!t){ kw.sort = eval("("+t+")"); } + t = ga("valueFn"); + if(!!t){ kw.valueFn = dfl.lambda(t); } + return o; + } + return null; + }; + + return ChartWidget; +}); + +}, +'dojox/lang/functional':function(){ +define("dojox/lang/functional", ["./functional/lambda", "./functional/array", "./functional/object"], function(df){ + return df; +}); + +}, +'dojox/charting/scaler/common':function(){ +define("dojox/charting/scaler/common", ["dojo/_base/lang"], function(lang){ + + var eq = function(/*Number*/ a, /*Number*/ b){ + // summary: compare two FP numbers for equality + return Math.abs(a - b) <= 1e-6 * (Math.abs(a) + Math.abs(b)); // Boolean + }; + + var common = lang.getObject("dojox.charting.scaler.common", true); + + var testedModules = {}; + + return lang.mixin(common, { + doIfLoaded: function(moduleName, ifloaded, ifnotloaded){ + if(testedModules[moduleName] == undefined){ + try{ + testedModules[moduleName] = require(moduleName); + }catch(e){ + testedModules[moduleName] = null; + } + } + if(testedModules[moduleName]){ + return ifloaded(testedModules[moduleName]); + }else{ + return ifnotloaded(); + } + }, + findString: function(/*String*/ val, /*Array*/ text){ + val = val.toLowerCase(); + for(var i = 0; i < text.length; ++i){ + if(val == text[i]){ return true; } + } + return false; + }, + getNumericLabel: function(/*Number*/ number, /*Number*/ precision, /*Object*/ kwArgs){ + var def = ""; + common.doIfLoaded("dojo/number", function(numberLib){ + def = (kwArgs.fixed ? numberLib.format(number, {places : precision < 0 ? -precision : 0}) : + numberLib.format(number)) || ""; + }, function(){ + def = kwArgs.fixed ? number.toFixed(precision < 0 ? -precision : 0) : number.toString(); + }); + if(kwArgs.labelFunc){ + var r = kwArgs.labelFunc(def, number, precision); + if(r){ return r; } + // else fall through to the regular labels search + } + if(kwArgs.labels){ + // classic binary search + var l = kwArgs.labels, lo = 0, hi = l.length; + while(lo < hi){ + var mid = Math.floor((lo + hi) / 2), val = l[mid].value; + if(val < number){ + lo = mid + 1; + }else{ + hi = mid; + } + } + // lets take into account FP errors + if(lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + --lo; + if(lo >= 0 && lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + lo += 2; + if(lo < l.length && eq(l[lo].value, number)){ + return l[lo].text; + } + // otherwise we will produce a number + } + return def; + } + }); +}); + +}, +'dojox/charting/axis2d/common':function(){ +define("dojox/charting/axis2d/common", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/window", "dojo/dom-geometry", "dojox/gfx"], + function(lang, html, win, domGeom, g){ + + var common = lang.getObject("dojox.charting.axis2d.common", true); + + var clearNode = function(s){ + s.marginLeft = "0px"; + s.marginTop = "0px"; + s.marginRight = "0px"; + s.marginBottom = "0px"; + s.paddingLeft = "0px"; + s.paddingTop = "0px"; + s.paddingRight = "0px"; + s.paddingBottom = "0px"; + s.borderLeftWidth = "0px"; + s.borderTopWidth = "0px"; + s.borderRightWidth = "0px"; + s.borderBottomWidth = "0px"; + }; + + var getBoxWidth = function(n){ + // marginBox is incredibly slow, so avoid it if we can + if(n["getBoundingClientRect"]){ + var bcr = n.getBoundingClientRect(); + return bcr.width || (bcr.right - bcr.left); + }else{ + return domGeom.getMarginBox(n).w; + } + }; + + return lang.mixin(common, { + // summary: + // Common methods to be used by any axis. This is considered "static". + createText: { + gfx: function(chart, creator, x, y, align, text, font, fontColor){ + // summary: + // Use dojox.gfx to create any text. + // chart: dojox.charting.Chart + // The chart to create the text into. + // creator: dojox.gfx.Surface + // The graphics surface to use for creating the text. + // x: Number + // Where to create the text along the x axis (CSS left). + // y: Number + // Where to create the text along the y axis (CSS top). + // align: String + // How to align the text. Can be "left", "right", "center". + // text: String + // The text to render. + // font: String + // The font definition, a la CSS "font". + // fontColor: String|dojo.Color + // The color of the resultant text. + // returns: dojox.gfx.Text + // The resultant GFX object. + return creator.createText({ + x: x, y: y, text: text, align: align + }).setFont(font).setFill(fontColor); // dojox.gfx.Text + }, + html: function(chart, creator, x, y, align, text, font, fontColor, labelWidth){ + // summary: + // Use the HTML DOM to create any text. + // chart: dojox.charting.Chart + // The chart to create the text into. + // creator: dojox.gfx.Surface + // The graphics surface to use for creating the text. + // x: Number + // Where to create the text along the x axis (CSS left). + // y: Number + // Where to create the text along the y axis (CSS top). + // align: String + // How to align the text. Can be "left", "right", "center". + // text: String + // The text to render. + // font: String + // The font definition, a la CSS "font". + // fontColor: String|dojo.Color + // The color of the resultant text. + // labelWidth: Number? + // The maximum width of the resultant DOM node. + // returns: DOMNode + // The resultant DOMNode (a "div" element). + + // setup the text node + var p = win.doc.createElement("div"), s = p.style, boxWidth; + // bidi support, if this function exists the module was loaded + if(chart.getTextDir){ + p.dir = chart.getTextDir(text); + } + clearNode(s); + s.font = font; + p.innerHTML = String(text).replace(/\s/g, " "); + s.color = fontColor; + // measure the size + s.position = "absolute"; + s.left = "-10000px"; + win.body().appendChild(p); + var size = g.normalizedLength(g.splitFontString(font).size); + + // do we need to calculate the label width? + if(!labelWidth){ + boxWidth = getBoxWidth(p); + } + // when the textDir is rtl, but the UI ltr needs + // to recalculate the starting point + if(p.dir == "rtl"){ + x += labelWidth ? labelWidth : boxWidth; + } + + // new settings for the text node + win.body().removeChild(p); + + s.position = "relative"; + if(labelWidth){ + s.width = labelWidth + "px"; + // s.border = "1px dotted grey"; + switch(align){ + case "middle": + s.textAlign = "center"; + s.left = (x - labelWidth / 2) + "px"; + break; + case "end": + s.textAlign = "right"; + s.left = (x - labelWidth) + "px"; + break; + default: + s.left = x + "px"; + s.textAlign = "left"; + break; + } + }else{ + switch(align){ + case "middle": + s.left = Math.floor(x - boxWidth / 2) + "px"; + // s.left = Math.floor(x - p.offsetWidth / 2) + "px"; + break; + case "end": + s.left = Math.floor(x - boxWidth) + "px"; + // s.left = Math.floor(x - p.offsetWidth) + "px"; + break; + //case "start": + default: + s.left = Math.floor(x) + "px"; + break; + } + } + s.top = Math.floor(y - size) + "px"; + s.whiteSpace = "nowrap"; // hack for WebKit + // setup the wrapper node + var wrap = win.doc.createElement("div"), w = wrap.style; + clearNode(w); + w.width = "0px"; + w.height = "0px"; + // insert nodes + wrap.appendChild(p) + chart.node.insertBefore(wrap, chart.node.firstChild); + return wrap; // DOMNode + } + } + }); +}); + +}, +'dijit/_TemplatedMixin':function(){ +define("dijit/_TemplatedMixin", [ + "dojo/_base/lang", // lang.getObject + "dojo/touch", + "./_WidgetBase", + "dojo/string", // string.substitute string.trim + "dojo/cache", // dojo.cache + "dojo/_base/array", // array.forEach + "dojo/_base/declare", // declare + "dojo/dom-construct", // domConstruct.destroy, domConstruct.toDom + "dojo/_base/sniff", // has("ie") + "dojo/_base/unload", // unload.addOnWindowUnload + "dojo/_base/window" // win.doc +], function(lang, touch, _WidgetBase, string, cache, array, declare, domConstruct, has, unload, win) { + +/*===== + var _WidgetBase = dijit._WidgetBase; +=====*/ + + // module: + // dijit/_TemplatedMixin + // summary: + // Mixin for widgets that are instantiated from a template + + var _TemplatedMixin = declare("dijit._TemplatedMixin", null, { + // summary: + // Mixin for widgets that are instantiated from a template + + // templateString: [protected] String + // A string that represents the widget template. + // Use in conjunction with dojo.cache() to load from a file. + templateString: null, + + // templatePath: [protected deprecated] String + // Path to template (HTML file) for this widget relative to dojo.baseUrl. + // Deprecated: use templateString with require([... "dojo/text!..."], ...) instead + templatePath: null, + + // skipNodeCache: [protected] Boolean + // If using a cached widget template nodes poses issues for a + // particular widget class, it can set this property to ensure + // that its template is always re-built from a string + _skipNodeCache: false, + + // _earlyTemplatedStartup: Boolean + // A fallback to preserve the 1.0 - 1.3 behavior of children in + // templates having their startup called before the parent widget + // fires postCreate. Defaults to 'false', causing child widgets to + // have their .startup() called immediately before a parent widget + // .startup(), but always after the parent .postCreate(). Set to + // 'true' to re-enable to previous, arguably broken, behavior. + _earlyTemplatedStartup: false, + +/*===== + // _attachPoints: [private] String[] + // List of widget attribute names associated with data-dojo-attach-point=... in the + // template, ex: ["containerNode", "labelNode"] + _attachPoints: [], + =====*/ + +/*===== + // _attachEvents: [private] Handle[] + // List of connections associated with data-dojo-attach-event=... in the + // template + _attachEvents: [], + =====*/ + + constructor: function(){ + this._attachPoints = []; + this._attachEvents = []; + }, + + _stringRepl: function(tmpl){ + // summary: + // Does substitution of ${foo} type properties in template string + // tags: + // private + var className = this.declaredClass, _this = this; + // Cache contains a string because we need to do property replacement + // do the property replacement + return string.substitute(tmpl, this, function(value, key){ + if(key.charAt(0) == '!'){ value = lang.getObject(key.substr(1), false, _this); } + if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide + if(value == null){ return ""; } + + // Substitution keys beginning with ! will skip the transform step, + // in case a user wishes to insert unescaped markup, e.g. ${!foo} + return key.charAt(0) == "!" ? value : + // Safer substitution, see heading "Attribute values" in + // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2 + value.toString().replace(/"/g,"""); //TODO: add &? use encodeXML method? + }, this); + }, + + buildRendering: function(){ + // summary: + // Construct the UI for this widget from a template, setting this.domNode. + // tags: + // protected + + if(!this.templateString){ + this.templateString = cache(this.templatePath, {sanitize: true}); + } + + // Lookup cached version of template, and download to cache if it + // isn't there already. Returns either a DomNode or a string, depending on + // whether or not the template contains ${foo} replacement parameters. + var cached = _TemplatedMixin.getCachedTemplate(this.templateString, this._skipNodeCache); + + var node; + if(lang.isString(cached)){ + node = domConstruct.toDom(this._stringRepl(cached)); + if(node.nodeType != 1){ + // Flag common problems such as templates with multiple top level nodes (nodeType == 11) + throw new Error("Invalid template: " + cached); + } + }else{ + // if it's a node, all we have to do is clone it + node = cached.cloneNode(true); + } + + this.domNode = node; + + // Call down to _Widget.buildRendering() to get base classes assigned + // TODO: change the baseClass assignment to _setBaseClassAttr + this.inherited(arguments); + + // recurse through the node, looking for, and attaching to, our + // attachment points and events, which should be defined on the template node. + this._attachTemplateNodes(node, function(n,p){ return n.getAttribute(p); }); + + this._beforeFillContent(); // hook for _WidgetsInTemplateMixin + + this._fillContent(this.srcNodeRef); + }, + + _beforeFillContent: function(){ + }, + + _fillContent: function(/*DomNode*/ source){ + // summary: + // Relocate source contents to templated container node. + // this.containerNode must be able to receive children, or exceptions will be thrown. + // tags: + // protected + var dest = this.containerNode; + if(source && dest){ + while(source.hasChildNodes()){ + dest.appendChild(source.firstChild); + } + } + }, + + _attachTemplateNodes: function(rootNode, getAttrFunc){ + // summary: + // Iterate through the template and attach functions and nodes accordingly. + // Alternately, if rootNode is an array of widgets, then will process data-dojo-attach-point + // etc. for those widgets. + // description: + // Map widget properties and functions to the handlers specified in + // the dom node and it's descendants. This function iterates over all + // nodes and looks for these properties: + // * dojoAttachPoint/data-dojo-attach-point + // * dojoAttachEvent/data-dojo-attach-event + // rootNode: DomNode|Widget[] + // the node to search for properties. All children will be searched. + // getAttrFunc: Function + // a function which will be used to obtain property for a given + // DomNode/Widget + // tags: + // private + + var nodes = lang.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*")); + var x = lang.isArray(rootNode) ? 0 : -1; + for(; x<nodes.length; x++){ + var baseNode = (x == -1) ? rootNode : nodes[x]; + if(this.widgetsInTemplate && (getAttrFunc(baseNode, "dojoType") || getAttrFunc(baseNode, "data-dojo-type"))){ + continue; + } + // Process data-dojo-attach-point + var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point"); + if(attachPoint){ + var point, points = attachPoint.split(/\s*,\s*/); + while((point = points.shift())){ + if(lang.isArray(this[point])){ + this[point].push(baseNode); + }else{ + this[point]=baseNode; + } + this._attachPoints.push(point); + } + } + + // Process data-dojo-attach-event + var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event"); + if(attachEvent){ + // NOTE: we want to support attributes that have the form + // "domEvent: nativeEvent; ..." + var event, events = attachEvent.split(/\s*,\s*/); + var trim = lang.trim; + while((event = events.shift())){ + if(event){ + var thisFunc = null; + if(event.indexOf(":") != -1){ + // oh, if only JS had tuple assignment + var funcNameArr = event.split(":"); + event = trim(funcNameArr[0]); + thisFunc = trim(funcNameArr[1]); + }else{ + event = trim(event); + } + if(!thisFunc){ + thisFunc = event; + } + // Map "press", "move" and "release" to keys.touch, keys.move, keys.release + this._attachEvents.push(this.connect(baseNode, touch[event] || event, thisFunc)); + } + } + } + } + }, + + destroyRendering: function(){ + // Delete all attach points to prevent IE6 memory leaks. + array.forEach(this._attachPoints, function(point){ + delete this[point]; + }, this); + this._attachPoints = []; + + // And same for event handlers + array.forEach(this._attachEvents, this.disconnect, this); + this._attachEvents = []; + + this.inherited(arguments); + } + }); + + // key is templateString; object is either string or DOM tree + _TemplatedMixin._templateCache = {}; + + _TemplatedMixin.getCachedTemplate = function(templateString, alwaysUseString){ + // summary: + // Static method to get a template based on the templatePath or + // templateString key + // templateString: String + // The template + // alwaysUseString: Boolean + // Don't cache the DOM tree for this template, even if it doesn't have any variables + // returns: Mixed + // Either string (if there are ${} variables that need to be replaced) or just + // a DOM tree (if the node can be cloned directly) + + // is it already cached? + var tmplts = _TemplatedMixin._templateCache; + var key = templateString; + var cached = tmplts[key]; + if(cached){ + try{ + // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value + if(!cached.ownerDocument || cached.ownerDocument == win.doc){ + // string or node of the same document + return cached; + } + }catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded + domConstruct.destroy(cached); + } + + templateString = string.trim(templateString); + + if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){ + // there are variables in the template so all we can do is cache the string + return (tmplts[key] = templateString); //String + }else{ + // there are no variables in the template so we can cache the DOM tree + var node = domConstruct.toDom(templateString); + if(node.nodeType != 1){ + throw new Error("Invalid template: " + templateString); + } + return (tmplts[key] = node); //Node + } + }; + + if(has("ie")){ + unload.addOnWindowUnload(function(){ + var cache = _TemplatedMixin._templateCache; + for(var key in cache){ + var value = cache[key]; + if(typeof value == "object"){ // value is either a string or a DOM node template + domConstruct.destroy(value); + } + delete cache[key]; + } + }); + } + + // These arguments can be specified for widgets which are used in templates. + // Since any widget can be specified as sub widgets in template, mix it + // into the base widget class. (This is a hack, but it's effective.) + lang.extend(_WidgetBase,{ + dojoAttachEvent: "", + dojoAttachPoint: "" + }); + + return _TemplatedMixin; +}); + +}, +'dojox/lang/functional/object':function(){ +define(["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/window", "./lambda"], function(dojo, lang, win, df){ + +// This module adds high-level functions and related constructs: +// - object/dictionary helpers + +// Defined methods: +// - take any valid lambda argument as the functional argument +// - skip all attributes that are present in the empty object +// (IE and/or 3rd-party libraries). + + var empty = {}; + +/*===== + var df = dojox.lang.functional; + =====*/ + lang.mixin(df, { + // object helpers + keys: function(/*Object*/ obj){ + // summary: returns an array of all keys in the object + var t = []; + for(var i in obj){ + if(!(i in empty)){ + t.push(i); + } + } + return t; // Array + }, + values: function(/*Object*/ obj){ + // summary: returns an array of all values in the object + var t = []; + for(var i in obj){ + if(!(i in empty)){ + t.push(obj[i]); + } + } + return t; // Array + }, + filterIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates new object with all attributes that pass the test + // implemented by the provided function. + o = o || win.global; f = df.lambda(f); + var t = {}, v, i; + for(i in obj){ + if(!(i in empty)){ + v = obj[i]; + if(f.call(o, v, i, obj)){ t[i] = v; } + } + } + return t; // Object + }, + forIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: iterates over all object attributes. + o = o || win.global; f = df.lambda(f); + for(var i in obj){ + if(!(i in empty)){ + f.call(o, obj[i], i, obj); + } + } + return o; // Object + }, + mapIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){ + // summary: creates new object with the results of calling + // a provided function on every attribute in this object. + o = o || win.global; f = df.lambda(f); + var t = {}, i; + for(i in obj){ + if(!(i in empty)){ + t[i] = f.call(o, obj[i], i, obj); + } + } + return t; // Object + } + }); + + return df; +}); + +}, +'dojo/window':function(){ +define(["./_base/lang", "./_base/sniff", "./_base/window", "./dom", "./dom-geometry", "./dom-style"], + function(lang, has, baseWindow, dom, geom, style) { + +// module: +// dojo/window +// summary: +// TODOC + +var window = lang.getObject("dojo.window", true); + +/*===== +dojo.window = { + // summary: + // TODO +}; +window = dojo.window; +=====*/ + +window.getBox = function(){ + // summary: + // Returns the dimensions and scroll position of the viewable area of a browser window + + var + scrollRoot = (baseWindow.doc.compatMode == 'BackCompat') ? baseWindow.body() : baseWindow.doc.documentElement, + // get scroll position + scroll = geom.docScroll(), // scrollRoot.scrollTop/Left should work + w, h; + + if(has("touch")){ // if(scrollbars not supported) + var uiWindow = baseWindow.doc.parentWindow || baseWindow.doc.defaultView; // use UI window, not dojo.global window. baseWindow.doc.parentWindow probably not needed since it's not defined for webkit + // on mobile, scrollRoot.clientHeight <= uiWindow.innerHeight <= scrollRoot.offsetHeight, return uiWindow.innerHeight + w = uiWindow.innerWidth || scrollRoot.clientWidth; // || scrollRoot.clientXXX probably never evaluated + h = uiWindow.innerHeight || scrollRoot.clientHeight; + }else{ + // on desktops, scrollRoot.clientHeight <= scrollRoot.offsetHeight <= uiWindow.innerHeight, return scrollRoot.clientHeight + // uiWindow.innerWidth/Height includes the scrollbar and cannot be used + w = scrollRoot.clientWidth; + h = scrollRoot.clientHeight; + } + return { + l: scroll.x, + t: scroll.y, + w: w, + h: h + }; +}; + +window.get = function(doc){ + // summary: + // Get window object associated with document doc + + // In some IE versions (at least 6.0), document.parentWindow does not return a + // reference to the real window object (maybe a copy), so we must fix it as well + // We use IE specific execScript to attach the real window reference to + // document._parentWindow for later use + if(has("ie") && window !== document.parentWindow){ + /* + In IE 6, only the variable "window" can be used to connect events (others + may be only copies). + */ + doc.parentWindow.execScript("document._parentWindow = window;", "Javascript"); + //to prevent memory leak, unset it after use + //another possibility is to add an onUnload handler which seems overkill to me (liucougar) + var win = doc._parentWindow; + doc._parentWindow = null; + return win; // Window + } + + return doc.parentWindow || doc.defaultView; // Window +}; + +window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){ + // summary: + // Scroll the passed node into view, if it is not already. + + // don't rely on node.scrollIntoView working just because the function is there + + try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method + node = dom.byId(node); + var doc = node.ownerDocument || baseWindow.doc, + body = doc.body || baseWindow.body(), + html = doc.documentElement || body.parentNode, + isIE = has("ie"), isWK = has("webkit"); + // if an untested browser, then use the native method + if((!(has("mozilla") || isIE || isWK || has("opera")) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){ + node.scrollIntoView(false); // short-circuit to native if possible + return; + } + var backCompat = doc.compatMode == 'BackCompat', + clientAreaRoot = (isIE >= 9 && node.ownerDocument.parentWindow.frameElement) + ? ((html.clientHeight > 0 && html.clientWidth > 0 && (body.clientHeight == 0 || body.clientWidth == 0 || body.clientHeight > html.clientHeight || body.clientWidth > html.clientWidth)) ? html : body) + : (backCompat ? body : html), + scrollRoot = isWK ? body : clientAreaRoot, + rootWidth = clientAreaRoot.clientWidth, + rootHeight = clientAreaRoot.clientHeight, + rtl = !geom.isBodyLtr(), + nodePos = pos || geom.position(node), + el = node.parentNode, + isFixed = function(el){ + return ((isIE <= 6 || (isIE && backCompat))? false : (style.get(el, 'position').toLowerCase() == "fixed")); + }; + if(isFixed(node)){ return; } // nothing to do + + while(el){ + if(el == body){ el = scrollRoot; } + var elPos = geom.position(el), + fixedPos = isFixed(el); + + if(el == scrollRoot){ + elPos.w = rootWidth; elPos.h = rootHeight; + if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x + if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0 + if(elPos.y < 0 || !isIE){ elPos.y = 0; } + }else{ + var pb = geom.getPadBorderExtents(el); + elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t; + var clientSize = el.clientWidth, + scrollBarSize = elPos.w - clientSize; + if(clientSize > 0 && scrollBarSize > 0){ + elPos.w = clientSize; + elPos.x += (rtl && (isIE || el.clientLeft > pb.l/*Chrome*/)) ? scrollBarSize : 0; + } + clientSize = el.clientHeight; + scrollBarSize = elPos.h - clientSize; + if(clientSize > 0 && scrollBarSize > 0){ + elPos.h = clientSize; + } + } + if(fixedPos){ // bounded by viewport, not parents + if(elPos.y < 0){ + elPos.h += elPos.y; elPos.y = 0; + } + if(elPos.x < 0){ + elPos.w += elPos.x; elPos.x = 0; + } + if(elPos.y + elPos.h > rootHeight){ + elPos.h = rootHeight - elPos.y; + } + if(elPos.x + elPos.w > rootWidth){ + elPos.w = rootWidth - elPos.x; + } + } + // calculate overflow in all 4 directions + var l = nodePos.x - elPos.x, // beyond left: < 0 + t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0 + r = l + nodePos.w - elPos.w, // beyond right: > 0 + bot = t + nodePos.h - elPos.h; // beyond bottom: > 0 + if(r * l > 0){ + var s = Math[l < 0? "max" : "min"](l, r); + if(rtl && ((isIE == 8 && !backCompat) || isIE >= 9)){ s = -s; } + nodePos.x += el.scrollLeft; + el.scrollLeft += s; + nodePos.x -= el.scrollLeft; + } + if(bot * t > 0){ + nodePos.y += el.scrollTop; + el.scrollTop += Math[t < 0? "max" : "min"](t, bot); + nodePos.y -= el.scrollTop; + } + el = (el != scrollRoot) && !fixedPos && el.parentNode; + } + }catch(error){ + console.error('scrollIntoView: ' + error); + node.scrollIntoView(false); + } +}; + +return window; +}); + +}, +'dojox/charting/axis2d/Default':function(){ +define("dojox/charting/axis2d/Default", ["dojo/_base/lang", "dojo/_base/array","dojo/_base/sniff", "dojo/_base/declare", + "dojo/_base/connect", "dojo/_base/html", "dojo/dom-geometry", "./Invisible", + "../scaler/common", "../scaler/linear", "./common", "dojox/gfx", "dojox/lang/utils"], + function(lang, arr, has, declare, connect, html, domGeom, Invisible, scommon, + lin, acommon, g, du){ + + /*===== + dojox.charting.axis2d.__AxisCtorArgs = function( + vertical, fixUpper, fixLower, natural, leftBottom, + includeZero, fixed, majorLabels, minorTicks, minorLabels, microTicks, htmlLabels, + min, max, from, to, majorTickStep, minorTickStep, microTickStep, + labels, labelFunc, maxLabelSize, + stroke, majorTick, minorTick, microTick, tick, + font, fontColor + ){ + // summary: + // Optional arguments used in the definition of an axis. + // + // vertical: Boolean? + // A flag that says whether an axis is vertical (i.e. y axis) or horizontal. Default is false (horizontal). + // fixUpper: String? + // Align the greatest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none". + // fixLower: String? + // Align the smallest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none". + // natural: Boolean? + // Ensure tick marks are made on "natural" numbers. Defaults to false. + // leftBottom: Boolean? + // The position of a vertical axis; if true, will be placed against the left-bottom corner of the chart. Defaults to true. + // includeZero: Boolean? + // Include 0 on the axis rendering. Default is false. + // fixed: Boolean? + // Force all axis labels to be fixed numbers. Default is true. + // majorLabels: Boolean? + // Flag to draw all labels at major ticks. Default is true. + // minorTicks: Boolean? + // Flag to draw minor ticks on an axis. Default is true. + // minorLabels: Boolean? + // Flag to draw labels on minor ticks. Default is true. + // microTicks: Boolean? + // Flag to draw micro ticks on an axis. Default is false. + // htmlLabels: Boolean? + // Flag to use HTML (as opposed to the native vector graphics engine) to draw labels. Default is true. + // min: Number? + // The smallest value on an axis. Default is 0. + // max: Number? + // The largest value on an axis. Default is 1. + // from: Number? + // Force the chart to render data visible from this value. Default is 0. + // to: Number? + // Force the chart to render data visible to this value. Default is 1. + // majorTickStep: Number? + // The amount to skip before a major tick is drawn. Default is 4. + // minorTickStep: Number? + // The amount to skip before a minor tick is drawn. Default is 2. + // microTickStep: Number? + // The amount to skip before a micro tick is drawn. Default is 1. + // labels: Object[]? + // An array of labels for major ticks, with corresponding numeric values, ordered by value. + // labelFunc: Function? + // An optional function used to compute label values. + // maxLabelSize: Number? + // The maximum size, in pixels, for a label. To be used with the optional label function. + // stroke: dojox.gfx.Stroke? + // An optional stroke to be used for drawing an axis. + // majorTick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a major tick. + // minorTick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a minor tick. + // microTick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a micro tick. + // tick: Object? + // An object containing a dojox.gfx.Stroke, and a length (number) for a tick. + // font: String? + // An optional font definition (as used in the CSS font property) for labels. + // fontColor: String|dojo.Color? + // An optional color to be used in drawing labels. + // enableCache: Boolean? + // Whether the ticks and labels are cached from one rendering to another. This improves the rendering performance of + // successive rendering but penalize the first rendering. For labels it is only working with gfx labels + // not html ones. Default false. + + this.vertical = vertical; + this.fixUpper = fixUpper; + this.fixLower = fixLower; + this.natural = natural; + this.leftBottom = leftBottom; + this.includeZero = includeZero; + this.fixed = fixed; + this.majorLabels = majorLabels; + this.minorTicks = minorTicks; + this.minorLabels = minorLabels; + this.microTicks = microTicks; + this.htmlLabels = htmlLabels; + this.min = min; + this.max = max; + this.from = from; + this.to = to; + this.majorTickStep = majorTickStep; + this.minorTickStep = minorTickStep; + this.microTickStep = microTickStep; + this.labels = labels; + this.labelFunc = labelFunc; + this.maxLabelSize = maxLabelSize; + this.stroke = stroke; + this.majorTick = majorTick; + this.minorTick = minorTick; + this.microTick = microTick; + this.tick = tick; + this.font = font; + this.fontColor = fontColor; + this.enableCache = enableCache; + } + var Invisible = dojox.charting.axis2d.Invisible + =====*/ + + var labelGap = 4, // in pixels + centerAnchorLimit = 45; // in degrees + + return declare("dojox.charting.axis2d.Default", Invisible, { + // summary: + // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details. + // + // defaultParams: Object + // The default parameters used to define any axis. + // optionalParams: Object + // Any optional parameters needed to define an axis. + + /* + // TODO: the documentation tools need these to be pre-defined in order to pick them up + // correctly, but the code here is partially predicated on whether or not the properties + // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT + + // opt: Object + // The actual options used to define this axis, created at initialization. + // scalar: Object + // The calculated helper object to tell charts how to draw an axis and any data. + // ticks: Object + // The calculated tick object that helps a chart draw the scaling on an axis. + // dirty: Boolean + // The state of the axis (whether it needs to be redrawn or not) + // scale: Number + // The current scale of the axis. + // offset: Number + // The current offset of the axis. + + opt: null, + scalar: null, + ticks: null, + dirty: true, + scale: 1, + offset: 0, + */ + defaultParams: { + vertical: false, // true for vertical axis + fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none" + fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none" + natural: false, // all tick marks should be made on natural numbers + leftBottom: true, // position of the axis, used with "vertical" + includeZero: false, // 0 should be included + fixed: true, // all labels are fixed numbers + majorLabels: true, // draw major labels + minorTicks: true, // draw minor ticks + minorLabels: true, // draw minor labels + microTicks: false, // draw micro ticks + rotation: 0, // label rotation angle in degrees + htmlLabels: true, // use HTML to draw labels + enableCache: false // whether we cache or not + }, + optionalParams: { + min: 0, // minimal value on this axis + max: 1, // maximal value on this axis + from: 0, // visible from this value + to: 1, // visible to this value + majorTickStep: 4, // major tick step + minorTickStep: 2, // minor tick step + microTickStep: 1, // micro tick step + labels: [], // array of labels for major ticks + // with corresponding numeric values + // ordered by values + labelFunc: null, // function to compute label values + maxLabelSize: 0, // size in px. For use with labelFunc + maxLabelCharCount: 0, // size in word count. + trailingSymbol: null, + + // TODO: add support for minRange! + // minRange: 1, // smallest distance from min allowed on the axis + + // theme components + stroke: {}, // stroke for an axis + majorTick: {}, // stroke + length for a tick + minorTick: {}, // stroke + length for a tick + microTick: {}, // stroke + length for a tick + tick: {}, // stroke + length for a tick + font: "", // font for labels + fontColor: "", // color for labels as a string + title: "", // axis title + titleGap: 0, // gap between axis title and axis label + titleFont: "", // axis title font + titleFontColor: "", // axis title font color + titleOrientation: "" // "axis" means the title facing the axis, "away" means facing away + }, + + constructor: function(chart, kwArgs){ + // summary: + // The constructor for an axis. + // chart: dojox.charting.Chart + // The chart the axis belongs to. + // kwArgs: dojox.charting.axis2d.__AxisCtorArgs? + // Any optional keyword arguments to be used to define this axis. + this.opt = lang.clone(this.defaultParams); + du.updateWithObject(this.opt, kwArgs); + du.updateWithPattern(this.opt, kwArgs, this.optionalParams); + if(this.opt.enableCache){ + this._textFreePool = []; + this._lineFreePool = []; + this._textUsePool = []; + this._lineUsePool = []; + } + }, + getOffsets: function(){ + // summary: + // Get the physical offset values for this axis (used in drawing data series). + // returns: Object + // The calculated offsets in the form of { l, r, t, b } (left, right, top, bottom). + var s = this.scaler, offsets = { l: 0, r: 0, t: 0, b: 0 }; + if(!s){ + return offsets; + } + var o = this.opt, labelWidth = 0, a, b, c, d, + gl = scommon.getNumericLabel, + offset = 0, ma = s.major, mi = s.minor, + ta = this.chart.theme.axis, + // TODO: we use one font --- of major tick, we need to use major and minor fonts + taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), + taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont), + taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15, + taMajorTick = this.chart.theme.getTick("major", o), + taMinorTick = this.chart.theme.getTick("minor", o), + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0, + rotation = o.rotation % 360, leftBottom = o.leftBottom, + cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), + sinr = Math.abs(Math.sin(rotation * Math.PI / 180)); + this.trailingSymbol = (o.trailingSymbol === undefined || o.trailingSymbol === null) ? this.trailingSymbol : o.trailingSymbol; + if(rotation < 0){ + rotation += 360; + } + + if(size){ + // we need width of all labels + if(this.labels){ + labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount); + }else{ + labelWidth = this._groupLabelWidth([ + gl(ma.start, ma.prec, o), + gl(ma.start + ma.count * ma.tick, ma.prec, o), + gl(mi.start, mi.prec, o), + gl(mi.start + mi.count * mi.tick, mi.prec, o) + ], taFont, o.maxLabelCharCount); + } + labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth; + if(this.vertical){ + var side = leftBottom ? "l" : "r"; + switch(rotation){ + case 0: + case 180: + offsets[side] = labelWidth; + offsets.t = offsets.b = size / 2; + break; + case 90: + case 270: + offsets[side] = size; + offsets.t = offsets.b = labelWidth / 2; + break; + default: + if(rotation <= centerAnchorLimit || (180 < rotation && rotation <= (180 + centerAnchorLimit))){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "t" : "b"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "b" : "t"] = size * cosr / 2; + }else if(rotation > (360 - centerAnchorLimit) || (180 > rotation && rotation > (180 - centerAnchorLimit))){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "b" : "t"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "t" : "b"] = size * cosr / 2; + }else if(rotation < 90 || (180 < rotation && rotation < 270)){ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "t" : "b"] = size * cosr + labelWidth * sinr; + }else{ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "b" : "t"] = size * cosr + labelWidth * sinr; + } + break; + } + offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0); + }else{ + var side = leftBottom ? "b" : "t"; + switch(rotation){ + case 0: + case 180: + offsets[side] = size; + offsets.l = offsets.r = labelWidth / 2; + break; + case 90: + case 270: + offsets[side] = labelWidth; + offsets.l = offsets.r = size / 2; + break; + default: + if((90 - centerAnchorLimit) <= rotation && rotation <= 90 || (270 - centerAnchorLimit) <= rotation && rotation <= 270){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "r" : "l"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "l" : "r"] = size * cosr / 2; + }else if(90 <= rotation && rotation <= (90 + centerAnchorLimit) || 270 <= rotation && rotation <= (270 + centerAnchorLimit)){ + offsets[side] = size * sinr / 2 + labelWidth * cosr; + offsets[leftBottom ? "l" : "r"] = size * cosr / 2 + labelWidth * sinr; + offsets[leftBottom ? "r" : "l"] = size * cosr / 2; + }else if(rotation < centerAnchorLimit || (180 < rotation && rotation < (180 - centerAnchorLimit))){ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "r" : "l"] = size * cosr + labelWidth * sinr; + }else{ + offsets[side] = size * sinr + labelWidth * cosr; + offsets[leftBottom ? "l" : "r"] = size * cosr + labelWidth * sinr; + } + break; + } + offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0); + } + } + if(labelWidth){ + this._cachedLabelWidth = labelWidth; + } + return offsets; // Object + }, + cleanGroup: function(creator){ + if(this.opt.enableCache && this.group){ + this._lineFreePool = this._lineFreePool.concat(this._lineUsePool); + this._lineUsePool = []; + this._textFreePool = this._textFreePool.concat(this._textUsePool); + this._textUsePool = []; + } + this.inherited(arguments); + }, + createText: function(labelType, creator, x, y, align, textContent, font, fontColor, labelWidth){ + if(!this.opt.enableCache || labelType=="html"){ + return acommon.createText[labelType]( + this.chart, + creator, + x, + y, + align, + textContent, + font, + fontColor, + labelWidth + ); + } + var text; + if (this._textFreePool.length > 0){ + text = this._textFreePool.pop(); + text.setShape({x: x, y: y, text: textContent, align: align}); + // For now all items share the same font, no need to re-set it + //.setFont(font).setFill(fontColor); + // was cleared, add it back + creator.add(text); + }else{ + text = acommon.createText[labelType]( + this.chart, + creator, + x, + y, + align, + textContent, + font, + fontColor, + labelWidth + ); } + this._textUsePool.push(text); + return text; + }, + createLine: function(creator, params){ + var line; + if(this.opt.enableCache && this._lineFreePool.length > 0){ + line = this._lineFreePool.pop(); + line.setShape(params); + // was cleared, add it back + creator.add(line); + }else{ + line = creator.createLine(params); + } + if(this.opt.enableCache){ + this._lineUsePool.push(line); + } + return line; + }, + render: function(dim, offsets){ + // summary: + // Render/draw the axis. + // dim: Object + // An object of the form { width, height}. + // offsets: Object + // An object of the form { l, r, t, b }. + // returns: dojox.charting.axis2d.Default + // The reference to the axis for functional chaining. + if(!this.dirty){ + return this; // dojox.charting.axis2d.Default + } + // prepare variable + var o = this.opt, ta = this.chart.theme.axis, leftBottom = o.leftBottom, rotation = o.rotation % 360, + start, stop, titlePos, titleRotation=0, titleOffset, axisVector, tickVector, anchorOffset, labelOffset, labelAlign, + + // TODO: we use one font --- of major tick, we need to use major and minor fonts + taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font), + taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont), + // TODO: we use one font color --- we need to use different colors + taFontColor = o.fontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "black", + taTitleFontColor = o.titleFontColor || (ta.tick && ta.tick.titleFontColor) || "black", + taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15, + taTitleOrientation = o.titleOrientation || (ta.tick && ta.tick.titleOrientation) || "axis", + taMajorTick = this.chart.theme.getTick("major", o), + taMinorTick = this.chart.theme.getTick("minor", o), + taMicroTick = this.chart.theme.getTick("micro", o), + + tickSize = Math.max(taMajorTick.length, taMinorTick.length, taMicroTick.length), + taStroke = "stroke" in o ? o.stroke : ta.stroke, + size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, + cosr = Math.abs(Math.cos(rotation * Math.PI / 180)), + sinr = Math.abs(Math.sin(rotation * Math.PI / 180)), + tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0; + if(rotation < 0){ + rotation += 360; + } + if(this.vertical){ + start = {y: dim.height - offsets.b}; + stop = {y: offsets.t}; + titlePos = {y: (dim.height - offsets.b + offsets.t)/2}; + titleOffset = size * sinr + (this._cachedLabelWidth || 0) * cosr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap; + axisVector = {x: 0, y: -1}; + labelOffset = {x: 0, y: 0}; + tickVector = {x: 1, y: 0}; + anchorOffset = {x: labelGap, y: 0}; + switch(rotation){ + case 0: + labelAlign = "end"; + labelOffset.y = size * 0.4; + break; + case 90: + labelAlign = "middle"; + labelOffset.x = -size; + break; + case 180: + labelAlign = "start"; + labelOffset.y = -size * 0.4; + break; + case 270: + labelAlign = "middle"; + break; + default: + if(rotation < centerAnchorLimit){ + labelAlign = "end"; + labelOffset.y = size * 0.4; + }else if(rotation < 90){ + labelAlign = "end"; + labelOffset.y = size * 0.4; + }else if(rotation < (180 - centerAnchorLimit)){ + labelAlign = "start"; + }else if(rotation < (180 + centerAnchorLimit)){ + labelAlign = "start"; + labelOffset.y = -size * 0.4; + }else if(rotation < 270){ + labelAlign = "start"; + labelOffset.x = leftBottom ? 0 : size * 0.4; + }else if(rotation < (360 - centerAnchorLimit)){ + labelAlign = "end"; + labelOffset.x = leftBottom ? 0 : size * 0.4; + }else{ + labelAlign = "end"; + labelOffset.y = size * 0.4; + } + } + if(leftBottom){ + start.x = stop.x = offsets.l; + titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 90 : 270; + titlePos.x = offsets.l - titleOffset + (titleRotation == 270 ? tsize : 0); + tickVector.x = -1; + anchorOffset.x = -anchorOffset.x; + }else{ + start.x = stop.x = dim.width - offsets.r; + titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 90 : 270; + titlePos.x = dim.width - offsets.r + titleOffset - (titleRotation == 270 ? 0 : tsize); + switch(labelAlign){ + case "start": + labelAlign = "end"; + break; + case "end": + labelAlign = "start"; + break; + case "middle": + labelOffset.x += size; + break; + } + } + }else{ + start = {x: offsets.l}; + stop = {x: dim.width - offsets.r}; + titlePos = {x: (dim.width - offsets.r + offsets.l)/2}; + titleOffset = size * cosr + (this._cachedLabelWidth || 0) * sinr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap; + axisVector = {x: 1, y: 0}; + labelOffset = {x: 0, y: 0}; + tickVector = {x: 0, y: 1}; + anchorOffset = {x: 0, y: labelGap}; + switch(rotation){ + case 0: + labelAlign = "middle"; + labelOffset.y = size; + break; + case 90: + labelAlign = "start"; + labelOffset.x = -size * 0.4; + break; + case 180: + labelAlign = "middle"; + break; + case 270: + labelAlign = "end"; + labelOffset.x = size * 0.4; + break; + default: + if(rotation < (90 - centerAnchorLimit)){ + labelAlign = "start"; + labelOffset.y = leftBottom ? size : 0; + }else if(rotation < (90 + centerAnchorLimit)){ + labelAlign = "start"; + labelOffset.x = -size * 0.4; + }else if(rotation < 180){ + labelAlign = "start"; + labelOffset.y = leftBottom ? 0 : -size; + }else if(rotation < (270 - centerAnchorLimit)){ + labelAlign = "end"; + labelOffset.y = leftBottom ? 0 : -size; + }else if(rotation < (270 + centerAnchorLimit)){ + labelAlign = "end"; + labelOffset.y = leftBottom ? size * 0.4 : 0; + }else{ + labelAlign = "end"; + labelOffset.y = leftBottom ? size : 0; + } + } + if(leftBottom){ + start.y = stop.y = dim.height - offsets.b; + titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 180 : 0; + titlePos.y = dim.height - offsets.b + titleOffset - (titleRotation ? tsize : 0); + }else{ + start.y = stop.y = offsets.t; + titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 180 : 0; + titlePos.y = offsets.t - titleOffset + (titleRotation ? 0 : tsize); + tickVector.y = -1; + anchorOffset.y = -anchorOffset.y; + switch(labelAlign){ + case "start": + labelAlign = "end"; + break; + case "end": + labelAlign = "start"; + break; + case "middle": + labelOffset.y -= size; + break; + } + } + } + + // render shapes + + this.cleanGroup(); + + try{ + var s = this.group, + c = this.scaler, + t = this.ticks, + canLabel, + f = lin.getTransformerFromModel(this.scaler), + // GFX Canvas now supports labels, so let's _not_ fallback to HTML anymore on canvas, just use + // HTML labels if explicitly asked + no rotation + no IE + no Opera + labelType = (!o.title || !titleRotation) && !rotation && this.opt.htmlLabels && !has("ie") && !has("opera") ? "html" : "gfx", + dx = tickVector.x * taMajorTick.length, + dy = tickVector.y * taMajorTick.length; + + s.createLine({ + x1: start.x, + y1: start.y, + x2: stop.x, + y2: stop.y + }).setStroke(taStroke); + + //create axis title + if(o.title){ + var axisTitle = acommon.createText[labelType]( + this.chart, + s, + titlePos.x, + titlePos.y, + "middle", + o.title, + taTitleFont, + taTitleFontColor + ); + if(labelType == "html"){ + this.htmlElements.push(axisTitle); + }else{ + //as soon as rotation is provided, labelType won't be "html" + //rotate gfx labels + axisTitle.setTransform(g.matrix.rotategAt(titleRotation, titlePos.x, titlePos.y)); + } + } + + // go out nicely instead of try/catch + if(t==null){ + this.dirty = false; + return this; + } + + arr.forEach(t.major, function(tick){ + var offset = f(tick.value), elem, + x = start.x + axisVector.x * offset, + y = start.y + axisVector.y * offset; + this.createLine(s, { + x1: x, y1: y, + x2: x + dx, + y2: y + dy + }).setStroke(taMajorTick); + if(tick.label){ + var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : { + text: tick.label, + truncated: false + }; + label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label; + elem = this.createText(labelType, + s, + x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x), + y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y), + labelAlign, + label.text, + taFont, + taFontColor + //this._cachedLabelWidth + ); + + // if bidi support was required, the textDir is "auto" and truncation + // took place, we need to update the dir of the element for cases as: + // Fool label: 111111W (W for bidi character) + // truncated label: 11... + // in this case for auto textDir the dir will be "ltr" which is wrong. + if(this.chart.truncateBidi && label.truncated){ + this.chart.truncateBidi(elem, tick.label, labelType); + } + label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType); + if(labelType == "html"){ + this.htmlElements.push(elem); + }else if(rotation){ + elem.setTransform([ + {dx: labelOffset.x, dy: labelOffset.y}, + g.matrix.rotategAt( + rotation, + x + dx + anchorOffset.x, + y + dy + anchorOffset.y + ) + ]); + } + } + }, this); + + dx = tickVector.x * taMinorTick.length; + dy = tickVector.y * taMinorTick.length; + canLabel = c.minMinorStep <= c.minor.tick * c.bounds.scale; + arr.forEach(t.minor, function(tick){ + var offset = f(tick.value), elem, + x = start.x + axisVector.x * offset, + y = start.y + axisVector.y * offset; + this.createLine(s, { + x1: x, y1: y, + x2: x + dx, + y2: y + dy + }).setStroke(taMinorTick); + if(canLabel && tick.label){ + var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : { + text: tick.label, + truncated: false + }; + label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label; + elem = this.createText(labelType, + s, + x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x), + y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y), + labelAlign, + label.text, + taFont, + taFontColor + //this._cachedLabelWidth + ); + // if bidi support was required, the textDir is "auto" and truncation + // took place, we need to update the dir of the element for cases as: + // Fool label: 111111W (W for bidi character) + // truncated label: 11... + // in this case for auto textDir the dir will be "ltr" which is wrong. + if(this.chart.getTextDir && label.truncated){ + this.chart.truncateBidi(elem, tick.label, labelType); + } + label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType); + if(labelType == "html"){ + this.htmlElements.push(elem); + }else if(rotation){ + elem.setTransform([ + {dx: labelOffset.x, dy: labelOffset.y}, + g.matrix.rotategAt( + rotation, + x + dx + anchorOffset.x, + y + dy + anchorOffset.y + ) + ]); + } + } + }, this); + + dx = tickVector.x * taMicroTick.length; + dy = tickVector.y * taMicroTick.length; + arr.forEach(t.micro, function(tick){ + var offset = f(tick.value), elem, + x = start.x + axisVector.x * offset, + y = start.y + axisVector.y * offset; + this.createLine(s, { + x1: x, y1: y, + x2: x + dx, + y2: y + dy + }).setStroke(taMicroTick); + }, this); + }catch(e){ + // squelch + } + + this.dirty = false; + return this; // dojox.charting.axis2d.Default + }, + labelTooltip: function(elem, chart, label, truncatedLabel, font, elemType){ + var modules = ["dijit/Tooltip"]; + var aroundRect = {type: "rect"}, position = ["above", "below"], + fontWidth = g._base._getTextBox(truncatedLabel, {font: font}).w || 0, + fontHeight = font ? g.normalizedLength(g.splitFontString(font).size) : 0; + if(elemType == "html"){ + lang.mixin(aroundRect, html.coords(elem.firstChild, true)); + aroundRect.width = Math.ceil(fontWidth); + aroundRect.height = Math.ceil(fontHeight); + this._events.push({ + shape: dojo, + handle: connect.connect(elem.firstChild, "onmouseover", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.show(label, aroundRect, position); + }); + }) + }); + this._events.push({ + shape: dojo, + handle: connect.connect(elem.firstChild, "onmouseout", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.hide(aroundRect); + }); + }) + }); + }else{ + var shp = elem.getShape(), + lt = html.coords(chart.node, true); + aroundRect = lang.mixin(aroundRect, { + x: shp.x - fontWidth / 2, + y: shp.y + }); + aroundRect.x += lt.x; + aroundRect.y += lt.y; + aroundRect.x = Math.round(aroundRect.x); + aroundRect.y = Math.round(aroundRect.y); + aroundRect.width = Math.ceil(fontWidth); + aroundRect.height = Math.ceil(fontHeight); + this._events.push({ + shape: elem, + handle: elem.connect("onmouseenter", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.show(label, aroundRect, position); + }); + }) + }); + this._events.push({ + shape: elem, + handle: elem.connect("onmouseleave", this, function(e){ + require(modules, function(Tooltip){ + Tooltip.hide(aroundRect); + }); + }) + }); + } + } + }); +}); + +}, +'dojox/charting/plot2d/ClusteredBars':function(){ +define("dojox/charting/plot2d/ClusteredBars", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "./Bars", "./common", + "dojox/lang/functional", "dojox/lang/functional/reversed", "dojox/lang/utils"], + function(lang, arr, declare, Bars, dc, df, dfr, du){ +/*===== +var Bars = dojox.charting.plot2d.Bars; +=====*/ + + var purgeGroup = dfr.lambda("item.purgeGroup()"); + + return declare("dojox.charting.plot2d.ClusteredBars", Bars, { + // summary: + // A plot representing grouped or clustered bars (horizontal bars) + render: function(dim, offsets){ + // summary: + // Run the calculations for any axes for this plot. + // dim: Object + // An object in the form of { width, height } + // offsets: Object + // An object of the form { l, r, t, b}. + // returns: dojox.charting.plot2d.ClusteredBars + // A reference to this plot for functional chaining. + if(this.zoom && !this.isDataDirty()){ + return this.performZoom(dim, offsets); + } + this.resetEvents(); + this.dirty = this.isDirty(); + if(this.dirty){ + arr.forEach(this.series, purgeGroup); + this._eventSeries = {}; + this.cleanGroup(); + var s = this.group; + df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); + } + var t = this.chart.theme, f, gap, height, thickness, + ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), + vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), + baseline = Math.max(0, this._hScaler.bounds.lower), + baselineWidth = ht(baseline), + events = this.events(); + f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt, this.series.length); + gap = f.gap; + height = thickness = f.size; + for(var i = this.series.length - 1; i >= 0; --i){ + var run = this.series[i], shift = thickness * (this.series.length - i - 1); + if(!this.dirty && !run.dirty){ + t.skip(); + this._reconnectEvents(run.name); + continue; + } + run.cleanGroup(); + var theme = t.next("bar", [this.opt, run]), s = run.group, + eventSeries = new Array(run.data.length); + for(var j = 0; j < run.data.length; ++j){ + var value = run.data[j]; + if(value !== null){ + var v = typeof value == "number" ? value : value.y, + hv = ht(v), + width = hv - baselineWidth, + w = Math.abs(width), + finalTheme = typeof value != "number" ? + t.addMixin(theme, "bar", value, true) : + t.post(theme, "bar"); + if(w >= 0 && height >= 1){ + var rect = { + x: offsets.l + (v < baseline ? hv : baselineWidth), + y: dim.height - offsets.b - vt(j + 1.5) + gap + shift, + width: w, height: height + }; + var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets); + specialFill = this._shapeFill(specialFill, rect); + var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke); + run.dyn.fill = shape.getFill(); + run.dyn.stroke = shape.getStroke(); + if(events){ + var o = { + element: "bar", + index: j, + run: run, + shape: shape, + x: v, + y: j + 1.5 + }; + this._connectEvents(o); + eventSeries[j] = o; + } + if(this.animate){ + this._animateBar(shape, offsets.l + baselineWidth, -width); + } + } + } + } + this._eventSeries[run.name] = eventSeries; + run.dirty = false; + } + this.dirty = false; + return this; // dojox.charting.plot2d.ClusteredBars + } + }); +}); + +}, +'dojox/charting/action2d/MoveSlice':function(){ +define("dojox/charting/action2d/MoveSlice", ["dojo/_base/connect", "dojo/_base/declare", "./PlotAction", "dojo/fx/easing", "dojox/gfx/matrix", + "dojox/gfx/fx", "dojox/lang/functional", "dojox/lang/functional/scan", "dojox/lang/functional/fold"], + function(hub, declare, PlotAction, dfe, m, gf, df, dfs, dff){ + + /*===== + dojo.declare("dojox.charting.action2d.__MoveSliceCtorArgs", dojox.charting.action2d.__PlotActionCtorArgs, { + // summary: + // Additional arguments for highlighting actions. + + // scale: Number? + // The amount to scale the pie slice. Default is 1.05. + scale: 1.05, + + // shift: Number? + // The amount in pixels to shift the pie slice. Default is 7. + shift: 7 + }); + var PlotAction = dojox.charting.action2d.PlotAction; + =====*/ + + var DEFAULT_SCALE = 1.05, + DEFAULT_SHIFT = 7; // px + + return declare("dojox.charting.action2d.MoveSlice", PlotAction, { + // summary: + // Create an action for a pie chart that moves and scales a pie slice. + + // the data description block for the widget parser + defaultParams: { + duration: 400, // duration of the action in ms + easing: dfe.backOut, // easing for the action + scale: DEFAULT_SCALE, // scale of magnification + shift: DEFAULT_SHIFT // shift of the slice + }, + optionalParams: {}, // no optional parameters + + constructor: function(chart, plot, kwArgs){ + // summary: + // Create the slice moving action and connect it to the plot. + // chart: dojox.charting.Chart + // The chart this action belongs to. + // plot: String? + // The plot this action is attached to. If not passed, "default" is assumed. + // kwArgs: dojox.charting.action2d.__MoveSliceCtorArgs? + // Optional keyword arguments object for setting parameters. + if(!kwArgs){ kwArgs = {}; } + this.scale = typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE; + this.shift = typeof kwArgs.shift == "number" ? kwArgs.shift : DEFAULT_SHIFT; + + this.connect(); + }, + + process: function(o){ + // summary: + // Process the action on the given object. + // o: dojox.gfx.Shape + // The object on which to process the slice moving action. + if(!o.shape || o.element != "slice" || !(o.type in this.overOutEvents)){ return; } + + if(!this.angles){ + // calculate the running total of slice angles + var startAngle = m._degToRad(o.plot.opt.startAngle); + if(typeof o.run.data[0] == "number"){ + this.angles = df.map(df.scanl(o.run.data, "+", startAngle), + "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0)); + }else{ + this.angles = df.map(df.scanl(o.run.data, "a + b.y", startAngle), + "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0)); + } + } + + var index = o.index, anim, startScale, endScale, startOffset, endOffset, + angle = (this.angles[index] + this.angles[index + 1]) / 2, + rotateTo0 = m.rotateAt(-angle, o.cx, o.cy), + rotateBack = m.rotateAt( angle, o.cx, o.cy); + + anim = this.anim[index]; + + if(anim){ + anim.action.stop(true); + }else{ + this.anim[index] = anim = {}; + } + + if(o.type == "onmouseover"){ + startOffset = 0; + endOffset = this.shift; + startScale = 1; + endScale = this.scale; + }else{ + startOffset = this.shift; + endOffset = 0; + startScale = this.scale; + endScale = 1; + } + + anim.action = gf.animateTransform({ + shape: o.shape, + duration: this.duration, + easing: this.easing, + transform: [ + rotateBack, + {name: "translate", start: [startOffset, 0], end: [endOffset, 0]}, + {name: "scaleAt", start: [startScale, o.cx, o.cy], end: [endScale, o.cx, o.cy]}, + rotateTo0 + ] + }); + + if(o.type == "onmouseout"){ + hub.connect(anim.action, "onEnd", this, function(){ + delete this.anim[index]; + }); + } + anim.action.play(); + }, + + reset: function(){ + delete this.angles; + } + }); +}); + +}, +'dojo/colors':function(){ +define(["./_base/kernel", "./_base/lang", "./_base/Color", "./_base/array"], function(dojo, lang, Color, ArrayUtil) { + // module: + // dojo/colors + // summary: + // TODOC + + var ColorExt = lang.getObject("dojo.colors", true); + +//TODO: this module appears to break naming conventions + +/*===== + lang.mixin(dojo, { + colors: { + // summary: Color utilities, extending Base dojo.Color + } + }); +=====*/ + + // this is a standard conversion prescribed by the CSS3 Color Module + var hue2rgb = function(m1, m2, h){ + if(h < 0){ ++h; } + if(h > 1){ --h; } + var h6 = 6 * h; + if(h6 < 1){ return m1 + (m2 - m1) * h6; } + if(2 * h < 1){ return m2; } + if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; } + return m1; + }; + // Override base Color.fromRgb with the impl in this module + dojo.colorFromRgb = Color.fromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){ + // summary: + // get rgb(a) array from css-style color declarations + // description: + // this function can handle all 4 CSS3 Color Module formats: rgb, + // rgba, hsl, hsla, including rgb(a) with percentage values. + var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/); + if(m){ + var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a; + if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){ + var r = c[0]; + if(r.charAt(r.length - 1) == "%"){ + // 3 rgb percentage values + a = ArrayUtil.map(c, function(x){ + return parseFloat(x) * 2.56; + }); + if(l == 4){ a[3] = c[3]; } + return Color.fromArray(a, obj); // dojo.Color + } + return Color.fromArray(c, obj); // dojo.Color + } + if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){ + // normalize hsl values + var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360, + S = parseFloat(c[1]) / 100, + L = parseFloat(c[2]) / 100, + // calculate rgb according to the algorithm + // recommended by the CSS3 Color Module + m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S, + m1 = 2 * L - m2; + a = [ + hue2rgb(m1, m2, H + 1 / 3) * 256, + hue2rgb(m1, m2, H) * 256, + hue2rgb(m1, m2, H - 1 / 3) * 256, + 1 + ]; + if(l == 4){ a[3] = c[3]; } + return Color.fromArray(a, obj); // dojo.Color + } + } + return null; // dojo.Color + }; + + var confine = function(c, low, high){ + // summary: + // sanitize a color component by making sure it is a number, + // and clamping it to valid values + c = Number(c); + return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number + }; + + Color.prototype.sanitize = function(){ + // summary: makes sure that the object has correct attributes + var t = this; + t.r = Math.round(confine(t.r, 0, 255)); + t.g = Math.round(confine(t.g, 0, 255)); + t.b = Math.round(confine(t.b, 0, 255)); + t.a = confine(t.a, 0, 1); + return this; // dojo.Color + }; + + ColorExt.makeGrey = Color.makeGrey = function(/*Number*/ g, /*Number?*/ a){ + // summary: creates a greyscale color with an optional alpha + return Color.fromArray([g, g, g, a]); // dojo.Color + }; + + // mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings + lang.mixin(Color.named, { + "aliceblue": [240,248,255], + "antiquewhite": [250,235,215], + "aquamarine": [127,255,212], + "azure": [240,255,255], + "beige": [245,245,220], + "bisque": [255,228,196], + "blanchedalmond": [255,235,205], + "blueviolet": [138,43,226], + "brown": [165,42,42], + "burlywood": [222,184,135], + "cadetblue": [95,158,160], + "chartreuse": [127,255,0], + "chocolate": [210,105,30], + "coral": [255,127,80], + "cornflowerblue": [100,149,237], + "cornsilk": [255,248,220], + "crimson": [220,20,60], + "cyan": [0,255,255], + "darkblue": [0,0,139], + "darkcyan": [0,139,139], + "darkgoldenrod": [184,134,11], + "darkgray": [169,169,169], + "darkgreen": [0,100,0], + "darkgrey": [169,169,169], + "darkkhaki": [189,183,107], + "darkmagenta": [139,0,139], + "darkolivegreen": [85,107,47], + "darkorange": [255,140,0], + "darkorchid": [153,50,204], + "darkred": [139,0,0], + "darksalmon": [233,150,122], + "darkseagreen": [143,188,143], + "darkslateblue": [72,61,139], + "darkslategray": [47,79,79], + "darkslategrey": [47,79,79], + "darkturquoise": [0,206,209], + "darkviolet": [148,0,211], + "deeppink": [255,20,147], + "deepskyblue": [0,191,255], + "dimgray": [105,105,105], + "dimgrey": [105,105,105], + "dodgerblue": [30,144,255], + "firebrick": [178,34,34], + "floralwhite": [255,250,240], + "forestgreen": [34,139,34], + "gainsboro": [220,220,220], + "ghostwhite": [248,248,255], + "gold": [255,215,0], + "goldenrod": [218,165,32], + "greenyellow": [173,255,47], + "grey": [128,128,128], + "honeydew": [240,255,240], + "hotpink": [255,105,180], + "indianred": [205,92,92], + "indigo": [75,0,130], + "ivory": [255,255,240], + "khaki": [240,230,140], + "lavender": [230,230,250], + "lavenderblush": [255,240,245], + "lawngreen": [124,252,0], + "lemonchiffon": [255,250,205], + "lightblue": [173,216,230], + "lightcoral": [240,128,128], + "lightcyan": [224,255,255], + "lightgoldenrodyellow": [250,250,210], + "lightgray": [211,211,211], + "lightgreen": [144,238,144], + "lightgrey": [211,211,211], + "lightpink": [255,182,193], + "lightsalmon": [255,160,122], + "lightseagreen": [32,178,170], + "lightskyblue": [135,206,250], + "lightslategray": [119,136,153], + "lightslategrey": [119,136,153], + "lightsteelblue": [176,196,222], + "lightyellow": [255,255,224], + "limegreen": [50,205,50], + "linen": [250,240,230], + "magenta": [255,0,255], + "mediumaquamarine": [102,205,170], + "mediumblue": [0,0,205], + "mediumorchid": [186,85,211], + "mediumpurple": [147,112,219], + "mediumseagreen": [60,179,113], + "mediumslateblue": [123,104,238], + "mediumspringgreen": [0,250,154], + "mediumturquoise": [72,209,204], + "mediumvioletred": [199,21,133], + "midnightblue": [25,25,112], + "mintcream": [245,255,250], + "mistyrose": [255,228,225], + "moccasin": [255,228,181], + "navajowhite": [255,222,173], + "oldlace": [253,245,230], + "olivedrab": [107,142,35], + "orange": [255,165,0], + "orangered": [255,69,0], + "orchid": [218,112,214], + "palegoldenrod": [238,232,170], + "palegreen": [152,251,152], + "paleturquoise": [175,238,238], + "palevioletred": [219,112,147], + "papayawhip": [255,239,213], + "peachpuff": [255,218,185], + "peru": [205,133,63], + "pink": [255,192,203], + "plum": [221,160,221], + "powderblue": [176,224,230], + "rosybrown": [188,143,143], + "royalblue": [65,105,225], + "saddlebrown": [139,69,19], + "salmon": [250,128,114], + "sandybrown": [244,164,96], + "seagreen": [46,139,87], + "seashell": [255,245,238], + "sienna": [160,82,45], + "skyblue": [135,206,235], + "slateblue": [106,90,205], + "slategray": [112,128,144], + "slategrey": [112,128,144], + "snow": [255,250,250], + "springgreen": [0,255,127], + "steelblue": [70,130,180], + "tan": [210,180,140], + "thistle": [216,191,216], + "tomato": [255,99,71], + "turquoise": [64,224,208], + "violet": [238,130,238], + "wheat": [245,222,179], + "whitesmoke": [245,245,245], + "yellowgreen": [154,205,50] + }); + + return Color; +}); + +}, +'dijit/Tooltip':function(){ +require({cache:{ +'url:dijit/templates/Tooltip.html':"<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" data-dojo-attach-point=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" data-dojo-attach-point=\"connectorNode\"></div\n></div>\n"}}); +define("dijit/Tooltip", [ + "dojo/_base/array", // array.forEach array.indexOf array.map + "dojo/_base/declare", // declare + "dojo/_base/fx", // fx.fadeIn fx.fadeOut + "dojo/dom", // dom.byId + "dojo/dom-class", // domClass.add + "dojo/dom-geometry", // domGeometry.getMarginBox domGeometry.position + "dojo/dom-style", // domStyle.set, domStyle.get + "dojo/_base/lang", // lang.hitch lang.isArrayLike + "dojo/_base/sniff", // has("ie") + "dojo/_base/window", // win.body + "./_base/manager", // manager.defaultDuration + "./place", + "./_Widget", + "./_TemplatedMixin", + "./BackgroundIframe", + "dojo/text!./templates/Tooltip.html", + "." // sets dijit.showTooltip etc. for back-compat +], function(array, declare, fx, dom, domClass, domGeometry, domStyle, lang, has, win, + manager, place, _Widget, _TemplatedMixin, BackgroundIframe, template, dijit){ + +/*===== + var _Widget = dijit._Widget; + var BackgroundIframe = dijit.BackgroundIframe; + var _TemplatedMixin = dijit._TemplatedMixin; +=====*/ + + // module: + // dijit/Tooltip + // summary: + // Defines dijit.Tooltip widget (to display a tooltip), showTooltip()/hideTooltip(), and _MasterTooltip + + + var MasterTooltip = declare("dijit._MasterTooltip", [_Widget, _TemplatedMixin], { + // summary: + // Internal widget that holds the actual tooltip markup, + // which occurs once per page. + // Called by Tooltip widgets which are just containers to hold + // the markup + // tags: + // protected + + // duration: Integer + // Milliseconds to fade in/fade out + duration: manager.defaultDuration, + + templateString: template, + + postCreate: function(){ + win.body().appendChild(this.domNode); + + this.bgIframe = new BackgroundIframe(this.domNode); + + // Setup fade-in and fade-out functions. + this.fadeIn = fx.fadeIn({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onShow") }); + this.fadeOut = fx.fadeOut({ node: this.domNode, duration: this.duration, onEnd: lang.hitch(this, "_onHide") }); + }, + + show: function(innerHTML, aroundNode, position, rtl, textDir){ + // summary: + // Display tooltip w/specified contents to right of specified node + // (To left if there's no space on the right, or if rtl == true) + // innerHTML: String + // Contents of the tooltip + // aroundNode: DomNode || dijit.__Rectangle + // Specifies that tooltip should be next to this node / area + // position: String[]? + // List of positions to try to position tooltip (ex: ["right", "above"]) + // rtl: Boolean? + // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true + // means "rtl"; specifies GUI direction, not text direction. + // textDir: String? + // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text. + + + if(this.aroundNode && this.aroundNode === aroundNode && this.containerNode.innerHTML == innerHTML){ + return; + } + + // reset width; it may have been set by orient() on a previous tooltip show() + this.domNode.width = "auto"; + + if(this.fadeOut.status() == "playing"){ + // previous tooltip is being hidden; wait until the hide completes then show new one + this._onDeck=arguments; + return; + } + this.containerNode.innerHTML=innerHTML; + + this.set("textDir", textDir); + this.containerNode.align = rtl? "right" : "left"; //fix the text alignment + + var pos = place.around(this.domNode, aroundNode, + position && position.length ? position : Tooltip.defaultPosition, !rtl, lang.hitch(this, "orient")); + + // Position the tooltip connector for middle alignment. + // This could not have been done in orient() since the tooltip wasn't positioned at that time. + var aroundNodeCoords = pos.aroundNodePos; + if(pos.corner.charAt(0) == 'M' && pos.aroundCorner.charAt(0) == 'M'){ + this.connectorNode.style.top = aroundNodeCoords.y + ((aroundNodeCoords.h - this.connectorNode.offsetHeight) >> 1) - pos.y + "px"; + this.connectorNode.style.left = ""; + }else if(pos.corner.charAt(1) == 'M' && pos.aroundCorner.charAt(1) == 'M'){ + this.connectorNode.style.left = aroundNodeCoords.x + ((aroundNodeCoords.w - this.connectorNode.offsetWidth) >> 1) - pos.x + "px"; + } + + // show it + domStyle.set(this.domNode, "opacity", 0); + this.fadeIn.play(); + this.isShowingNow = true; + this.aroundNode = aroundNode; + }, + + orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){ + // summary: + // Private function to set CSS for tooltip node based on which position it's in. + // This is called by the dijit popup code. It will also reduce the tooltip's + // width to whatever width is available + // tags: + // protected + this.connectorNode.style.top = ""; //reset to default + + //Adjust the spaceAvailable width, without changing the spaceAvailable object + var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth; + + node.className = "dijitTooltip " + + { + "MR-ML": "dijitTooltipRight", + "ML-MR": "dijitTooltipLeft", + "TM-BM": "dijitTooltipAbove", + "BM-TM": "dijitTooltipBelow", + "BL-TL": "dijitTooltipBelow dijitTooltipABLeft", + "TL-BL": "dijitTooltipAbove dijitTooltipABLeft", + "BR-TR": "dijitTooltipBelow dijitTooltipABRight", + "TR-BR": "dijitTooltipAbove dijitTooltipABRight", + "BR-BL": "dijitTooltipRight", + "BL-BR": "dijitTooltipLeft" + }[aroundCorner + "-" + tooltipCorner]; + + // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen + this.domNode.style.width = "auto"; + var size = domGeometry.getContentBox(this.domNode); + + var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w); + var widthWasReduced = width < size.w; + + this.domNode.style.width = width+"px"; + + //Adjust width for tooltips that have a really long word or a nowrap setting + if(widthWasReduced){ + this.containerNode.style.overflow = "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content + var scrollWidth = this.containerNode.scrollWidth; + this.containerNode.style.overflow = "visible"; //change it back + if(scrollWidth > width){ + scrollWidth = scrollWidth + domStyle.get(this.domNode,"paddingLeft") + domStyle.get(this.domNode,"paddingRight"); + this.domNode.style.width = scrollWidth + "px"; + } + } + + // Reposition the tooltip connector. + if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){ + var mb = domGeometry.getMarginBox(node); + var tooltipConnectorHeight = this.connectorNode.offsetHeight; + if(mb.h > spaceAvailable.h){ + // The tooltip starts at the top of the page and will extend past the aroundNode + var aroundNodePlacement = spaceAvailable.h - ((aroundNodeCoords.h + tooltipConnectorHeight) >> 1); + this.connectorNode.style.top = aroundNodePlacement + "px"; + this.connectorNode.style.bottom = ""; + }else{ + // Align center of connector with center of aroundNode, except don't let bottom + // of connector extend below bottom of tooltip content, or top of connector + // extend past top of tooltip content + this.connectorNode.style.bottom = Math.min( + Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0), + mb.h - tooltipConnectorHeight) + "px"; + this.connectorNode.style.top = ""; + } + }else{ + // reset the tooltip back to the defaults + this.connectorNode.style.top = ""; + this.connectorNode.style.bottom = ""; + } + + return Math.max(0, size.w - tooltipSpaceAvaliableWidth); + }, + + _onShow: function(){ + // summary: + // Called at end of fade-in operation + // tags: + // protected + if(has("ie")){ + // the arrow won't show up on a node w/an opacity filter + this.domNode.style.filter=""; + } + }, + + hide: function(aroundNode){ + // summary: + // Hide the tooltip + + if(this._onDeck && this._onDeck[1] == aroundNode){ + // this hide request is for a show() that hasn't even started yet; + // just cancel the pending show() + this._onDeck=null; + }else if(this.aroundNode === aroundNode){ + // this hide request is for the currently displayed tooltip + this.fadeIn.stop(); + this.isShowingNow = false; + this.aroundNode = null; + this.fadeOut.play(); + }else{ + // just ignore the call, it's for a tooltip that has already been erased + } + }, + + _onHide: function(){ + // summary: + // Called at end of fade-out operation + // tags: + // protected + + this.domNode.style.cssText=""; // to position offscreen again + this.containerNode.innerHTML=""; + if(this._onDeck){ + // a show request has been queued up; do it now + this.show.apply(this, this._onDeck); + this._onDeck=null; + } + }, + + _setAutoTextDir: function(/*Object*/node){ + // summary: + // Resolve "auto" text direction for children nodes + // tags: + // private + + this.applyTextDir(node, has("ie") ? node.outerText : node.textContent); + array.forEach(node.children, function(child){this._setAutoTextDir(child); }, this); + }, + + _setTextDirAttr: function(/*String*/ textDir){ + // summary: + // Setter for textDir. + // description: + // Users shouldn't call this function; they should be calling + // set('textDir', value) + // tags: + // private + + this._set("textDir", typeof textDir != 'undefined'? textDir : ""); + if (textDir == "auto"){ + this._setAutoTextDir(this.containerNode); + }else{ + this.containerNode.dir = this.textDir; + } + } + }); + + dijit.showTooltip = function(innerHTML, aroundNode, position, rtl, textDir){ + // summary: + // Static method to display tooltip w/specified contents in specified position. + // See description of dijit.Tooltip.defaultPosition for details on position parameter. + // If position is not specified then dijit.Tooltip.defaultPosition is used. + // innerHTML: String + // Contents of the tooltip + // aroundNode: dijit.__Rectangle + // Specifies that tooltip should be next to this node / area + // position: String[]? + // List of positions to try to position tooltip (ex: ["right", "above"]) + // rtl: Boolean? + // Corresponds to `WidgetBase.dir` attribute, where false means "ltr" and true + // means "rtl"; specifies GUI direction, not text direction. + // textDir: String? + // Corresponds to `WidgetBase.textdir` attribute; specifies direction of text. + if(!Tooltip._masterTT){ dijit._masterTT = Tooltip._masterTT = new MasterTooltip(); } + return Tooltip._masterTT.show(innerHTML, aroundNode, position, rtl, textDir); + }; + + dijit.hideTooltip = function(aroundNode){ + // summary: + // Static method to hide the tooltip displayed via showTooltip() + return Tooltip._masterTT && Tooltip._masterTT.hide(aroundNode); + }; + + var Tooltip = declare("dijit.Tooltip", _Widget, { + // summary: + // Pops up a tooltip (a help message) when you hover over a node. + + // label: String + // Text to display in the tooltip. + // Specified as innerHTML when creating the widget from markup. + label: "", + + // showDelay: Integer + // Number of milliseconds to wait after hovering over/focusing on the object, before + // the tooltip is displayed. + showDelay: 400, + + // connectId: String|String[] + // Id of domNode(s) to attach the tooltip to. + // When user hovers over specified dom node, the tooltip will appear. + connectId: [], + + // position: String[] + // See description of `dijit.Tooltip.defaultPosition` for details on position parameter. + position: [], + + _setConnectIdAttr: function(/*String|String[]*/ newId){ + // summary: + // Connect to specified node(s) + + // Remove connections to old nodes (if there are any) + array.forEach(this._connections || [], function(nested){ + array.forEach(nested, lang.hitch(this, "disconnect")); + }, this); + + // Make array of id's to connect to, excluding entries for nodes that don't exist yet, see startup() + this._connectIds = array.filter(lang.isArrayLike(newId) ? newId : (newId ? [newId] : []), + function(id){ return dom.byId(id); }); + + // Make connections + this._connections = array.map(this._connectIds, function(id){ + var node = dom.byId(id); + return [ + this.connect(node, "onmouseenter", "_onHover"), + this.connect(node, "onmouseleave", "_onUnHover"), + this.connect(node, "onfocus", "_onHover"), + this.connect(node, "onblur", "_onUnHover") + ]; + }, this); + + this._set("connectId", newId); + }, + + addTarget: function(/*DOMNODE || String*/ node){ + // summary: + // Attach tooltip to specified node if it's not already connected + + // TODO: remove in 2.0 and just use set("connectId", ...) interface + + var id = node.id || node; + if(array.indexOf(this._connectIds, id) == -1){ + this.set("connectId", this._connectIds.concat(id)); + } + }, + + removeTarget: function(/*DomNode || String*/ node){ + // summary: + // Detach tooltip from specified node + + // TODO: remove in 2.0 and just use set("connectId", ...) interface + + var id = node.id || node, // map from DOMNode back to plain id string + idx = array.indexOf(this._connectIds, id); + if(idx >= 0){ + // remove id (modifies original this._connectIds but that's OK in this case) + this._connectIds.splice(idx, 1); + this.set("connectId", this._connectIds); + } + }, + + buildRendering: function(){ + this.inherited(arguments); + domClass.add(this.domNode,"dijitTooltipData"); + }, + + startup: function(){ + this.inherited(arguments); + + // If this tooltip was created in a template, or for some other reason the specified connectId[s] + // didn't exist during the widget's initialization, then connect now. + var ids = this.connectId; + array.forEach(lang.isArrayLike(ids) ? ids : [ids], this.addTarget, this); + }, + + _onHover: function(/*Event*/ e){ + // summary: + // Despite the name of this method, it actually handles both hover and focus + // events on the target node, setting a timer to show the tooltip. + // tags: + // private + if(!this._showTimer){ + var target = e.target; + this._showTimer = setTimeout(lang.hitch(this, function(){this.open(target)}), this.showDelay); + } + }, + + _onUnHover: function(/*Event*/ /*===== e =====*/){ + // summary: + // Despite the name of this method, it actually handles both mouseleave and blur + // events on the target node, hiding the tooltip. + // tags: + // private + + // keep a tooltip open if the associated element still has focus (even though the + // mouse moved away) + if(this._focus){ return; } + + if(this._showTimer){ + clearTimeout(this._showTimer); + delete this._showTimer; + } + this.close(); + }, + + open: function(/*DomNode*/ target){ + // summary: + // Display the tooltip; usually not called directly. + // tags: + // private + + if(this._showTimer){ + clearTimeout(this._showTimer); + delete this._showTimer; + } + Tooltip.show(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight(), this.textDir); + + this._connectNode = target; + this.onShow(target, this.position); + }, + + close: function(){ + // summary: + // Hide the tooltip or cancel timer for show of tooltip + // tags: + // private + + if(this._connectNode){ + // if tooltip is currently shown + Tooltip.hide(this._connectNode); + delete this._connectNode; + this.onHide(); + } + if(this._showTimer){ + // if tooltip is scheduled to be shown (after a brief delay) + clearTimeout(this._showTimer); + delete this._showTimer; + } + }, + + onShow: function(/*===== target, position =====*/){ + // summary: + // Called when the tooltip is shown + // tags: + // callback + }, + + onHide: function(){ + // summary: + // Called when the tooltip is hidden + // tags: + // callback + }, + + uninitialize: function(){ + this.close(); + this.inherited(arguments); + } + }); + + Tooltip._MasterTooltip = MasterTooltip; // for monkey patching + Tooltip.show = dijit.showTooltip; // export function through module return value + Tooltip.hide = dijit.hideTooltip; // export function through module return value + + // dijit.Tooltip.defaultPosition: String[] + // This variable controls the position of tooltips, if the position is not specified to + // the Tooltip widget or *TextBox widget itself. It's an array of strings with the values + // possible for `dijit/place::around()`. The recommended values are: + // + // * before-centered: centers tooltip to the left of the anchor node/widget, or to the right + // in the case of RTL scripts like Hebrew and Arabic + // * after-centered: centers tooltip to the right of the anchor node/widget, or to the left + // in the case of RTL scripts like Hebrew and Arabic + // * above-centered: tooltip is centered above anchor node + // * below-centered: tooltip is centered above anchor node + // + // The list is positions is tried, in order, until a position is found where the tooltip fits + // within the viewport. + // + // Be careful setting this parameter. A value of "above-centered" may work fine until the user scrolls + // the screen so that there's no room above the target node. Nodes with drop downs, like + // DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure + // that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there + // is only room below (or above) the target node, but not both. + Tooltip.defaultPosition = ["after-centered", "before-centered"]; + + + return Tooltip; +}); + +}, +'dojox/charting/Element':function(){ +define("dojox/charting/Element", ["dojo/_base/lang", "dojo/_base/array", "dojo/dom-construct","dojo/_base/declare", "dojox/gfx", "dojox/gfx/utils", "dojox/gfx/shape"], + function(lang, arr, domConstruct, declare, gfx, utils, shape){ + + return declare("dojox.charting.Element", null, { + // summary: + // A base class that is used to build other elements of a chart, such as + // a series. + // chart: dojox.charting.Chart + // The parent chart for this element. + // group: dojox.gfx.Group + // The visual GFX group representing this element. + // htmlElement: Array + // Any DOMNodes used as a part of this element (such as HTML-based labels). + // dirty: Boolean + // A flag indicating whether or not this element needs to be rendered. + + chart: null, + group: null, + htmlElements: null, + dirty: true, + + constructor: function(chart){ + // summary: + // Creates a new charting element. + // chart: dojox.charting.Chart + // The chart that this element belongs to. + this.chart = chart; + this.group = null; + this.htmlElements = []; + this.dirty = true; + this.trailingSymbol = "..."; + this._events = []; + }, + createGroup: function(creator){ + // summary: + // Convenience function to create a new dojox.gfx.Group. + // creator: dojox.gfx.Surface? + // An optional surface in which to create this group. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + if(!creator){ creator = this.chart.surface; } + if(!this.group){ + this.group = creator.createGroup(); + } + return this; // dojox.charting.Element + }, + purgeGroup: function(){ + // summary: + // Clear any elements out of our group, and destroy the group. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + this.destroyHtmlElements(); + if(this.group){ + // since 1.7.x we need dispose shape otherwise there is a memoryleak + utils.forEach(this.group, function(child){ + shape.dispose(child); + }); + this.group.clear(); + this.group.removeShape(); + this.group = null; + } + this.dirty = true; + if(this._events.length){ + arr.forEach(this._events, function(item){ + item.shape.disconnect(item.handle); + }); + this._events = []; + } + return this; // dojox.charting.Element + }, + cleanGroup: function(creator){ + // summary: + // Clean any elements (HTML or GFX-based) out of our group, and create a new one. + // creator: dojox.gfx.Surface? + // An optional surface to work with. + // returns: dojox.charting.Element + // A reference to this object for functional chaining. + this.destroyHtmlElements(); + if(!creator){ creator = this.chart.surface; } + if(this.group){ + this.group.clear(); + }else{ + this.group = creator.createGroup(); + } + this.dirty = true; + return this; // dojox.charting.Element + }, + destroyHtmlElements: function(){ + // summary: + // Destroy any DOMNodes that may have been created as a part of this element. + if(this.htmlElements.length){ + arr.forEach(this.htmlElements, domConstruct.destroy); + this.htmlElements = []; + } + }, + destroy: function(){ + // summary: + // API addition to conform to the rest of the Dojo Toolkit's standard. + this.purgeGroup(); + }, + //text utilities + getTextWidth: function(s, font){ + return gfx._base._getTextBox(s, {font: font}).w || 0; + }, + getTextWithLimitLength: function(s, font, limitWidth, truncated){ + // summary: + // Get the truncated string based on the limited width in px(dichotomy algorithm) + // s: String? + // candidate text. + // font: String? + // text's font style. + // limitWidth: Number? + // text limited width in px. + // truncated: Boolean? + // whether the input text(s) has already been truncated. + // returns: Object + // { + // text: processed text, maybe truncated or not + // truncated: whether text has been truncated + // } + if (!s || s.length <= 0) { + return { + text: "", + truncated: truncated || false + }; + } + if(!limitWidth || limitWidth <= 0){ + return { + text: s, + truncated: truncated || false + }; + } + var delta = 2, + //golden section for dichotomy algorithm + trucPercentage = 0.618, + minStr = s.substring(0,1) + this.trailingSymbol, + minWidth = this.getTextWidth(minStr, font); + if (limitWidth <= minWidth) { + return { + text: minStr, + truncated: true + }; + } + var width = this.getTextWidth(s, font); + if(width <= limitWidth){ + return { + text: s, + truncated: truncated || false + }; + }else{ + var begin = 0, + end = s.length; + while(begin < end){ + if(end - begin <= delta ){ + while (this.getTextWidth(s.substring(0, begin) + this.trailingSymbol, font) > limitWidth) { + begin -= 1; + } + return { + text: (s.substring(0,begin) + this.trailingSymbol), + truncated: true + }; + } + var index = begin + Math.round((end - begin) * trucPercentage), + widthIntercepted = this.getTextWidth(s.substring(0, index), font); + if(widthIntercepted < limitWidth){ + begin = index; + end = end; + }else{ + begin = begin; + end = index; + } + } + } + }, + getTextWithLimitCharCount: function(s, font, wcLimit, truncated){ + // summary: + // Get the truncated string based on the limited character count(dichotomy algorithm) + // s: String? + // candidate text. + // font: String? + // text's font style. + // wcLimit: Number? + // text limited character count. + // truncated: Boolean? + // whether the input text(s) has already been truncated. + // returns: Object + // { + // text: processed text, maybe truncated or not + // truncated: whether text has been truncated + // } + if (!s || s.length <= 0) { + return { + text: "", + truncated: truncated || false + }; + } + if(!wcLimit || wcLimit <= 0 || s.length <= wcLimit){ + return { + text: s, + truncated: truncated || false + }; + } + return { + text: s.substring(0, wcLimit) + this.trailingSymbol, + truncated: true + }; + }, + // fill utilities + _plotFill: function(fill, dim, offsets){ + // process a plot-wide fill + if(!fill || !fill.type || !fill.space){ + return fill; + } + var space = fill.space; + switch(fill.type){ + case "linear": + if(space === "plot" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultLinearGradient, fill); + fill.space = space; + // process dimensions + if(space === "plot" || space === "shapeX"){ + // process Y + var span = dim.height - offsets.t - offsets.b; + fill.y1 = offsets.t + span * fill.y1 / 100; + fill.y2 = offsets.t + span * fill.y2 / 100; + } + if(space === "plot" || space === "shapeY"){ + // process X + var span = dim.width - offsets.l - offsets.r; + fill.x1 = offsets.l + span * fill.x1 / 100; + fill.x2 = offsets.l + span * fill.x2 / 100; + } + } + break; + case "radial": + if(space === "plot"){ + // this one is used exclusively for scatter charts + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultRadialGradient, fill); + fill.space = space; + // process both dimensions + var spanX = dim.width - offsets.l - offsets.r, + spanY = dim.height - offsets.t - offsets.b; + fill.cx = offsets.l + spanX * fill.cx / 100; + fill.cy = offsets.t + spanY * fill.cy / 100; + fill.r = fill.r * Math.sqrt(spanX * spanX + spanY * spanY) / 200; + } + break; + case "pattern": + if(space === "plot" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultPattern, fill); + fill.space = space; + // process dimensions + if(space === "plot" || space === "shapeX"){ + // process Y + var span = dim.height - offsets.t - offsets.b; + fill.y = offsets.t + span * fill.y / 100; + fill.height = span * fill.height / 100; + } + if(space === "plot" || space === "shapeY"){ + // process X + var span = dim.width - offsets.l - offsets.r; + fill.x = offsets.l + span * fill.x / 100; + fill.width = span * fill.width / 100; + } + } + break; + } + return fill; + }, + _shapeFill: function(fill, bbox){ + // process shape-specific fill + if(!fill || !fill.space){ + return fill; + } + var space = fill.space; + switch(fill.type){ + case "linear": + if(space === "shape" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultLinearGradient, fill); + fill.space = space; + // process dimensions + if(space === "shape" || space === "shapeX"){ + // process X + var span = bbox.width; + fill.x1 = bbox.x + span * fill.x1 / 100; + fill.x2 = bbox.x + span * fill.x2 / 100; + } + if(space === "shape" || space === "shapeY"){ + // process Y + var span = bbox.height; + fill.y1 = bbox.y + span * fill.y1 / 100; + fill.y2 = bbox.y + span * fill.y2 / 100; + } + } + break; + case "radial": + if(space === "shape"){ + // this one is used exclusively for bubble charts and pie charts + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultRadialGradient, fill); + fill.space = space; + // process both dimensions + fill.cx = bbox.x + bbox.width / 2; + fill.cy = bbox.y + bbox.height / 2; + fill.r = fill.r * bbox.width / 200; + } + break; + case "pattern": + if(space === "shape" || space === "shapeX" || space === "shapeY"){ + // clone a fill so we can modify properly directly + fill = gfx.makeParameters(gfx.defaultPattern, fill); + fill.space = space; + // process dimensions + if(space === "shape" || space === "shapeX"){ + // process X + var span = bbox.width; + fill.x = bbox.x + span * fill.x / 100; + fill.width = span * fill.width / 100; + } + if(space === "shape" || space === "shapeY"){ + // process Y + var span = bbox.height; + fill.y = bbox.y + span * fill.y / 100; + fill.height = span * fill.height / 100; + } + } + break; + } + return fill; + }, + _pseudoRadialFill: function(fill, center, radius, start, end){ + // process pseudo-radial fills + if(!fill || fill.type !== "radial" || fill.space !== "shape"){ + return fill; + } + // clone and normalize fill + var space = fill.space; + fill = gfx.makeParameters(gfx.defaultRadialGradient, fill); + fill.space = space; + if(arguments.length < 4){ + // process both dimensions + fill.cx = center.x; + fill.cy = center.y; + fill.r = fill.r * radius / 100; + return fill; + } + // convert to a linear gradient + var angle = arguments.length < 5 ? start : (end + start) / 2; + return { + type: "linear", + x1: center.x, + y1: center.y, + x2: center.x + fill.r * radius * Math.cos(angle) / 100, + y2: center.y + fill.r * radius * Math.sin(angle) / 100, + colors: fill.colors + }; + return fill; + } + }); +}); + +}, +'dijit/_WidgetBase':function(){ +define("dijit/_WidgetBase", [ + "require", // require.toUrl + "dojo/_base/array", // array.forEach array.map + "dojo/aspect", + "dojo/_base/config", // config.blankGif + "dojo/_base/connect", // connect.connect + "dojo/_base/declare", // declare + "dojo/dom", // dom.byId + "dojo/dom-attr", // domAttr.set domAttr.remove + "dojo/dom-class", // domClass.add domClass.replace + "dojo/dom-construct", // domConstruct.create domConstruct.destroy domConstruct.place + "dojo/dom-geometry", // isBodyLtr + "dojo/dom-style", // domStyle.set, domStyle.get + "dojo/_base/kernel", + "dojo/_base/lang", // mixin(), isArray(), etc. + "dojo/on", + "dojo/ready", + "dojo/Stateful", // Stateful + "dojo/topic", + "dojo/_base/window", // win.doc.createTextNode + "./registry" // registry.getUniqueId(), registry.findWidgets() +], function(require, array, aspect, config, connect, declare, + dom, domAttr, domClass, domConstruct, domGeometry, domStyle, kernel, + lang, on, ready, Stateful, topic, win, registry){ + +/*===== +var Stateful = dojo.Stateful; +=====*/ + +// module: +// dijit/_WidgetBase +// summary: +// Future base class for all Dijit widgets. + +// For back-compat, remove in 2.0. +if(!kernel.isAsync){ + ready(0, function(){ + var requires = ["dijit/_base/manager"]; + require(requires); // use indirection so modules not rolled into a build + }); +} + +// Nested hash listing attributes for each tag, all strings in lowercase. +// ex: {"div": {"style": true, "tabindex" true}, "form": { ... +var tagAttrs = {}; +function getAttrs(obj){ + var ret = {}; + for(var attr in obj){ + ret[attr.toLowerCase()] = true; + } + return ret; +} + +function nonEmptyAttrToDom(attr){ + // summary: + // Returns a setter function that copies the attribute to this.domNode, + // or removes the attribute from this.domNode, depending on whether the + // value is defined or not. + return function(val){ + domAttr[val ? "set" : "remove"](this.domNode, attr, val); + this._set(attr, val); + }; +} + +return declare("dijit._WidgetBase", Stateful, { + // summary: + // Future base class for all Dijit widgets. + // description: + // Future base class for all Dijit widgets. + // _Widget extends this class adding support for various features needed by desktop. + // + // Provides stubs for widget lifecycle methods for subclasses to extend, like postMixInProperties(), buildRendering(), + // postCreate(), startup(), and destroy(), and also public API methods like set(), get(), and watch(). + // + // Widgets can provide custom setters/getters for widget attributes, which are called automatically by set(name, value). + // For an attribute XXX, define methods _setXXXAttr() and/or _getXXXAttr(). + // + // _setXXXAttr can also be a string/hash/array mapping from a widget attribute XXX to the widget's DOMNodes: + // + // - DOM node attribute + // | _setFocusAttr: {node: "focusNode", type: "attribute"} + // | _setFocusAttr: "focusNode" (shorthand) + // | _setFocusAttr: "" (shorthand, maps to this.domNode) + // Maps this.focus to this.focusNode.focus, or (last example) this.domNode.focus + // + // - DOM node innerHTML + // | _setTitleAttr: { node: "titleNode", type: "innerHTML" } + // Maps this.title to this.titleNode.innerHTML + // + // - DOM node innerText + // | _setTitleAttr: { node: "titleNode", type: "innerText" } + // Maps this.title to this.titleNode.innerText + // + // - DOM node CSS class + // | _setMyClassAttr: { node: "domNode", type: "class" } + // Maps this.myClass to this.domNode.className + // + // If the value of _setXXXAttr is an array, then each element in the array matches one of the + // formats of the above list. + // + // If the custom setter is null, no action is performed other than saving the new value + // in the widget (in this). + // + // If no custom setter is defined for an attribute, then it will be copied + // to this.focusNode (if the widget defines a focusNode), or this.domNode otherwise. + // That's only done though for attributes that match DOMNode attributes (title, + // alt, aria-labelledby, etc.) + + // id: [const] String + // A unique, opaque ID string that can be assigned by users or by the + // system. If the developer passes an ID which is known not to be + // unique, the specified ID is ignored and the system-generated ID is + // used instead. + id: "", + _setIdAttr: "domNode", // to copy to this.domNode even for auto-generated id's + + // lang: [const] String + // Rarely used. Overrides the default Dojo locale used to render this widget, + // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute. + // Value must be among the list of locales specified during by the Dojo bootstrap, + // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us). + lang: "", + // set on domNode even when there's a focus node. but don't set lang="", since that's invalid. + _setLangAttr: nonEmptyAttrToDom("lang"), + + // dir: [const] String + // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir) + // attribute. Either left-to-right "ltr" or right-to-left "rtl". If undefined, widgets renders in page's + // default direction. + dir: "", + // set on domNode even when there's a focus node. but don't set dir="", since that's invalid. + _setDirAttr: nonEmptyAttrToDom("dir"), // to set on domNode even when there's a focus node + + // textDir: String + // Bi-directional support, the main variable which is responsible for the direction of the text. + // The text direction can be different than the GUI direction by using this parameter in creation + // of a widget. + // Allowed values: + // 1. "ltr" + // 2. "rtl" + // 3. "auto" - contextual the direction of a text defined by first strong letter. + // By default is as the page direction. + textDir: "", + + // class: String + // HTML class attribute + "class": "", + _setClassAttr: { node: "domNode", type: "class" }, + + // style: String||Object + // HTML style attributes as cssText string or name/value hash + style: "", + + // title: String + // HTML title attribute. + // + // For form widgets this specifies a tooltip to display when hovering over + // the widget (just like the native HTML title attribute). + // + // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer, + // etc., it's used to specify the tab label, accordion pane title, etc. + title: "", + + // tooltip: String + // When this widget's title attribute is used to for a tab label, accordion pane title, etc., + // this specifies the tooltip to appear when the mouse is hovered over that text. + tooltip: "", + + // baseClass: [protected] String + // Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate + // widget state. + baseClass: "", + + // srcNodeRef: [readonly] DomNode + // pointer to original DOM node + srcNodeRef: null, + + // domNode: [readonly] DomNode + // This is our visible representation of the widget! Other DOM + // Nodes may by assigned to other properties, usually through the + // template system's data-dojo-attach-point syntax, but the domNode + // property is the canonical "top level" node in widget UI. + domNode: null, + + // containerNode: [readonly] DomNode + // Designates where children of the source DOM node will be placed. + // "Children" in this case refers to both DOM nodes and widgets. + // For example, for myWidget: + // + // | <div data-dojo-type=myWidget> + // | <b> here's a plain DOM node + // | <span data-dojo-type=subWidget>and a widget</span> + // | <i> and another plain DOM node </i> + // | </div> + // + // containerNode would point to: + // + // | <b> here's a plain DOM node + // | <span data-dojo-type=subWidget>and a widget</span> + // | <i> and another plain DOM node </i> + // + // In templated widgets, "containerNode" is set via a + // data-dojo-attach-point assignment. + // + // containerNode must be defined for any widget that accepts innerHTML + // (like ContentPane or BorderContainer or even Button), and conversely + // is null for widgets that don't, like TextBox. + containerNode: null, + +/*===== + // _started: Boolean + // startup() has completed. + _started: false, +=====*/ + + // attributeMap: [protected] Object + // Deprecated. Instead of attributeMap, widget should have a _setXXXAttr attribute + // for each XXX attribute to be mapped to the DOM. + // + // attributeMap sets up a "binding" between attributes (aka properties) + // of the widget and the widget's DOM. + // Changes to widget attributes listed in attributeMap will be + // reflected into the DOM. + // + // For example, calling set('title', 'hello') + // on a TitlePane will automatically cause the TitlePane's DOM to update + // with the new title. + // + // attributeMap is a hash where the key is an attribute of the widget, + // and the value reflects a binding to a: + // + // - DOM node attribute + // | focus: {node: "focusNode", type: "attribute"} + // Maps this.focus to this.focusNode.focus + // + // - DOM node innerHTML + // | title: { node: "titleNode", type: "innerHTML" } + // Maps this.title to this.titleNode.innerHTML + // + // - DOM node innerText + // | title: { node: "titleNode", type: "innerText" } + // Maps this.title to this.titleNode.innerText + // + // - DOM node CSS class + // | myClass: { node: "domNode", type: "class" } + // Maps this.myClass to this.domNode.className + // + // If the value is an array, then each element in the array matches one of the + // formats of the above list. + // + // There are also some shorthands for backwards compatibility: + // - string --> { node: string, type: "attribute" }, for example: + // | "focusNode" ---> { node: "focusNode", type: "attribute" } + // - "" --> { node: "domNode", type: "attribute" } + attributeMap: {}, + + // _blankGif: [protected] String + // Path to a blank 1x1 image. + // Used by <img> nodes in templates that really get their image via CSS background-image. + _blankGif: config.blankGif || require.toUrl("dojo/resources/blank.gif"), + + //////////// INITIALIZATION METHODS /////////////////////////////////////// + + postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ + // summary: + // Kicks off widget instantiation. See create() for details. + // tags: + // private + this.create(params, srcNodeRef); + }, + + create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){ + // summary: + // Kick off the life-cycle of a widget + // params: + // Hash of initialization parameters for widget, including + // scalar values (like title, duration etc.) and functions, + // typically callbacks like onClick. + // srcNodeRef: + // If a srcNodeRef (DOM node) is specified: + // - use srcNodeRef.innerHTML as my contents + // - if this is a behavioral widget then apply behavior + // to that srcNodeRef + // - otherwise, replace srcNodeRef with my generated DOM + // tree + // description: + // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate, + // etc.), some of which of you'll want to override. See http://dojotoolkit.org/reference-guide/dijit/_WidgetBase.html + // for a discussion of the widget creation lifecycle. + // + // Of course, adventurous developers could override create entirely, but this should + // only be done as a last resort. + // tags: + // private + + // store pointer to original DOM tree + this.srcNodeRef = dom.byId(srcNodeRef); + + // For garbage collection. An array of listener handles returned by this.connect() / this.subscribe() + this._connects = []; + + // For widgets internal to this widget, invisible to calling code + this._supportingWidgets = []; + + // this is here for back-compat, remove in 2.0 (but check NodeList-instantiate.html test) + if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; } + + // mix in our passed parameters + if(params){ + this.params = params; + lang.mixin(this, params); + } + this.postMixInProperties(); + + // generate an id for the widget if one wasn't specified + // (be sure to do this before buildRendering() because that function might + // expect the id to be there.) + if(!this.id){ + this.id = registry.getUniqueId(this.declaredClass.replace(/\./g,"_")); + } + registry.add(this); + + this.buildRendering(); + + if(this.domNode){ + // Copy attributes listed in attributeMap into the [newly created] DOM for the widget. + // Also calls custom setters for all attributes with custom setters. + this._applyAttributes(); + + // If srcNodeRef was specified, then swap out original srcNode for this widget's DOM tree. + // For 2.0, move this after postCreate(). postCreate() shouldn't depend on the + // widget being attached to the DOM since it isn't when a widget is created programmatically like + // new MyWidget({}). See #11635. + var source = this.srcNodeRef; + if(source && source.parentNode && this.domNode !== source){ + source.parentNode.replaceChild(this.domNode, source); + } + } + + if(this.domNode){ + // Note: for 2.0 may want to rename widgetId to dojo._scopeName + "_widgetId", + // assuming that dojo._scopeName even exists in 2.0 + this.domNode.setAttribute("widgetId", this.id); + } + this.postCreate(); + + // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC. + if(this.srcNodeRef && !this.srcNodeRef.parentNode){ + delete this.srcNodeRef; + } + + this._created = true; + }, + + _applyAttributes: function(){ + // summary: + // Step during widget creation to copy widget attributes to the + // DOM according to attributeMap and _setXXXAttr objects, and also to call + // custom _setXXXAttr() methods. + // + // Skips over blank/false attribute values, unless they were explicitly specified + // as parameters to the widget, since those are the default anyway, + // and setting tabIndex="" is different than not setting tabIndex at all. + // + // For backwards-compatibility reasons attributeMap overrides _setXXXAttr when + // _setXXXAttr is a hash/string/array, but _setXXXAttr as a functions override attributeMap. + // tags: + // private + + // Get list of attributes where this.set(name, value) will do something beyond + // setting this[name] = value. Specifically, attributes that have: + // - associated _setXXXAttr() method/hash/string/array + // - entries in attributeMap. + var ctor = this.constructor, + list = ctor._setterAttrs; + if(!list){ + list = (ctor._setterAttrs = []); + for(var attr in this.attributeMap){ + list.push(attr); + } + + var proto = ctor.prototype; + for(var fxName in proto){ + if(fxName in this.attributeMap){ continue; } + var setterName = "_set" + fxName.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); }) + "Attr"; + if(setterName in proto){ + list.push(fxName); + } + } + } + + // Call this.set() for each attribute that was either specified as parameter to constructor, + // or was found above and has a default non-null value. For correlated attributes like value and displayedValue, the one + // specified as a parameter should take precedence, so apply attributes in this.params last. + // Particularly important for new DateTextBox({displayedValue: ...}) since DateTextBox's default value is + // NaN and thus is not ignored like a default value of "". + array.forEach(list, function(attr){ + if(this.params && attr in this.params){ + // skip this one, do it below + }else if(this[attr]){ + this.set(attr, this[attr]); + } + }, this); + for(var param in this.params){ + this.set(param, this[param]); + } + }, + + postMixInProperties: function(){ + // summary: + // Called after the parameters to the widget have been read-in, + // but before the widget template is instantiated. Especially + // useful to set properties that are referenced in the widget + // template. + // tags: + // protected + }, + + buildRendering: function(){ + // summary: + // Construct the UI for this widget, setting this.domNode. + // Most widgets will mixin `dijit._TemplatedMixin`, which implements this method. + // tags: + // protected + + if(!this.domNode){ + // Create root node if it wasn't created by _Templated + this.domNode = this.srcNodeRef || domConstruct.create('div'); + } + + // baseClass is a single class name or occasionally a space-separated list of names. + // Add those classes to the DOMNode. If RTL mode then also add with Rtl suffix. + // TODO: make baseClass custom setter + if(this.baseClass){ + var classes = this.baseClass.split(" "); + if(!this.isLeftToRight()){ + classes = classes.concat( array.map(classes, function(name){ return name+"Rtl"; })); + } + domClass.add(this.domNode, classes); + } + }, + + postCreate: function(){ + // summary: + // Processing after the DOM fragment is created + // description: + // Called after the DOM fragment has been created, but not necessarily + // added to the document. Do not include any operations which rely on + // node dimensions or placement. + // tags: + // protected + }, + + startup: function(){ + // summary: + // Processing after the DOM fragment is added to the document + // description: + // Called after a widget and its children have been created and added to the page, + // and all related widgets have finished their create() cycle, up through postCreate(). + // This is useful for composite widgets that need to control or layout sub-widgets. + // Many layout widgets can use this as a wiring phase. + if(this._started){ return; } + this._started = true; + array.forEach(this.getChildren(), function(obj){ + if(!obj._started && !obj._destroyed && lang.isFunction(obj.startup)){ + obj.startup(); + obj._started = true; + } + }); + }, + + //////////// DESTROY FUNCTIONS //////////////////////////////// + + destroyRecursive: function(/*Boolean?*/ preserveDom){ + // summary: + // Destroy this widget and its descendants + // description: + // This is the generic "destructor" function that all widget users + // should call to cleanly discard with a widget. Once a widget is + // destroyed, it is removed from the manager object. + // preserveDom: + // If true, this method will leave the original DOM structure + // alone of descendant Widgets. Note: This will NOT work with + // dijit._Templated widgets. + + this._beingDestroyed = true; + this.destroyDescendants(preserveDom); + this.destroy(preserveDom); + }, + + destroy: function(/*Boolean*/ preserveDom){ + // summary: + // Destroy this widget, but not its descendants. + // This method will, however, destroy internal widgets such as those used within a template. + // preserveDom: Boolean + // If true, this method will leave the original DOM structure alone. + // Note: This will not yet work with _Templated widgets + + this._beingDestroyed = true; + this.uninitialize(); + + // remove this.connect() and this.subscribe() listeners + var c; + while(c = this._connects.pop()){ + c.remove(); + } + + // destroy widgets created as part of template, etc. + var w; + while(w = this._supportingWidgets.pop()){ + if(w.destroyRecursive){ + w.destroyRecursive(); + }else if(w.destroy){ + w.destroy(); + } + } + + this.destroyRendering(preserveDom); + registry.remove(this.id); + this._destroyed = true; + }, + + destroyRendering: function(/*Boolean?*/ preserveDom){ + // summary: + // Destroys the DOM nodes associated with this widget + // preserveDom: + // If true, this method will leave the original DOM structure alone + // during tear-down. Note: this will not work with _Templated + // widgets yet. + // tags: + // protected + + if(this.bgIframe){ + this.bgIframe.destroy(preserveDom); + delete this.bgIframe; + } + + if(this.domNode){ + if(preserveDom){ + domAttr.remove(this.domNode, "widgetId"); + }else{ + domConstruct.destroy(this.domNode); + } + delete this.domNode; + } + + if(this.srcNodeRef){ + if(!preserveDom){ + domConstruct.destroy(this.srcNodeRef); + } + delete this.srcNodeRef; + } + }, + + destroyDescendants: function(/*Boolean?*/ preserveDom){ + // summary: + // Recursively destroy the children of this widget and their + // descendants. + // preserveDom: + // If true, the preserveDom attribute is passed to all descendant + // widget's .destroy() method. Not for use with _Templated + // widgets. + + // get all direct descendants and destroy them recursively + array.forEach(this.getChildren(), function(widget){ + if(widget.destroyRecursive){ + widget.destroyRecursive(preserveDom); + } + }); + }, + + uninitialize: function(){ + // summary: + // Stub function. Override to implement custom widget tear-down + // behavior. + // tags: + // protected + return false; + }, + + ////////////////// GET/SET, CUSTOM SETTERS, ETC. /////////////////// + + _setStyleAttr: function(/*String||Object*/ value){ + // summary: + // Sets the style attribute of the widget according to value, + // which is either a hash like {height: "5px", width: "3px"} + // or a plain string + // description: + // Determines which node to set the style on based on style setting + // in attributeMap. + // tags: + // protected + + var mapNode = this.domNode; + + // Note: technically we should revert any style setting made in a previous call + // to his method, but that's difficult to keep track of. + + if(lang.isObject(value)){ + domStyle.set(mapNode, value); + }else{ + if(mapNode.style.cssText){ + mapNode.style.cssText += "; " + value; + }else{ + mapNode.style.cssText = value; + } + } + + this._set("style", value); + }, + + _attrToDom: function(/*String*/ attr, /*String*/ value, /*Object?*/ commands){ + // summary: + // Reflect a widget attribute (title, tabIndex, duration etc.) to + // the widget DOM, as specified by commands parameter. + // If commands isn't specified then it's looked up from attributeMap. + // Note some attributes like "type" + // cannot be processed this way as they are not mutable. + // + // tags: + // private + + commands = arguments.length >= 3 ? commands : this.attributeMap[attr]; + + array.forEach(lang.isArray(commands) ? commands : [commands], function(command){ + + // Get target node and what we are doing to that node + var mapNode = this[command.node || command || "domNode"]; // DOM node + var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute + + switch(type){ + case "attribute": + if(lang.isFunction(value)){ // functions execute in the context of the widget + value = lang.hitch(this, value); + } + + // Get the name of the DOM node attribute; usually it's the same + // as the name of the attribute in the widget (attr), but can be overridden. + // Also maps handler names to lowercase, like onSubmit --> onsubmit + var attrName = command.attribute ? command.attribute : + (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr); + + domAttr.set(mapNode, attrName, value); + break; + case "innerText": + mapNode.innerHTML = ""; + mapNode.appendChild(win.doc.createTextNode(value)); + break; + case "innerHTML": + mapNode.innerHTML = value; + break; + case "class": + domClass.replace(mapNode, value, this[attr]); + break; + } + }, this); + }, + + get: function(name){ + // summary: + // Get a property from a widget. + // name: + // The property to get. + // description: + // Get a named property from a widget. The property may + // potentially be retrieved via a getter method. If no getter is defined, this + // just retrieves the object's property. + // + // For example, if the widget has properties `foo` and `bar` + // and a method named `_getFooAttr()`, calling: + // `myWidget.get("foo")` would be equivalent to calling + // `widget._getFooAttr()` and `myWidget.get("bar")` + // would be equivalent to the expression + // `widget.bar2` + var names = this._getAttrNames(name); + return this[names.g] ? this[names.g]() : this[name]; + }, + + set: function(name, value){ + // summary: + // Set a property on a widget + // name: + // The property to set. + // value: + // The value to set in the property. + // description: + // Sets named properties on a widget which may potentially be handled by a + // setter in the widget. + // + // For example, if the widget has properties `foo` and `bar` + // and a method named `_setFooAttr()`, calling + // `myWidget.set("foo", "Howdy!")` would be equivalent to calling + // `widget._setFooAttr("Howdy!")` and `myWidget.set("bar", 3)` + // would be equivalent to the statement `widget.bar = 3;` + // + // set() may also be called with a hash of name/value pairs, ex: + // + // | myWidget.set({ + // | foo: "Howdy", + // | bar: 3 + // | }); + // + // This is equivalent to calling `set(foo, "Howdy")` and `set(bar, 3)` + + if(typeof name === "object"){ + for(var x in name){ + this.set(x, name[x]); + } + return this; + } + var names = this._getAttrNames(name), + setter = this[names.s]; + if(lang.isFunction(setter)){ + // use the explicit setter + var result = setter.apply(this, Array.prototype.slice.call(arguments, 1)); + }else{ + // Mapping from widget attribute to DOMNode attribute/value/etc. + // Map according to: + // 1. attributeMap setting, if one exists (TODO: attributeMap deprecated, remove in 2.0) + // 2. _setFooAttr: {...} type attribute in the widget (if one exists) + // 3. apply to focusNode or domNode if standard attribute name, excluding funcs like onClick. + // Checks if an attribute is a "standard attribute" by whether the DOMNode JS object has a similar + // attribute name (ex: accept-charset attribute matches jsObject.acceptCharset). + // Note also that Tree.focusNode() is a function not a DOMNode, so test for that. + var defaultNode = this.focusNode && !lang.isFunction(this.focusNode) ? "focusNode" : "domNode", + tag = this[defaultNode].tagName, + attrsForTag = tagAttrs[tag] || (tagAttrs[tag] = getAttrs(this[defaultNode])), + map = name in this.attributeMap ? this.attributeMap[name] : + names.s in this ? this[names.s] : + ((names.l in attrsForTag && typeof value != "function") || + /^aria-|^data-|^role$/.test(name)) ? defaultNode : null; + if(map != null){ + this._attrToDom(name, value, map); + } + this._set(name, value); + } + return result || this; + }, + + _attrPairNames: {}, // shared between all widgets + _getAttrNames: function(name){ + // summary: + // Helper function for get() and set(). + // Caches attribute name values so we don't do the string ops every time. + // tags: + // private + + var apn = this._attrPairNames; + if(apn[name]){ return apn[name]; } + var uc = name.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); }); + return (apn[name] = { + n: name+"Node", + s: "_set"+uc+"Attr", // converts dashes to camel case, ex: accept-charset --> _setAcceptCharsetAttr + g: "_get"+uc+"Attr", + l: uc.toLowerCase() // lowercase name w/out dashes, ex: acceptcharset + }); + }, + + _set: function(/*String*/ name, /*anything*/ value){ + // summary: + // Helper function to set new value for specified attribute, and call handlers + // registered with watch() if the value has changed. + var oldValue = this[name]; + this[name] = value; + if(this._watchCallbacks && this._created && value !== oldValue){ + this._watchCallbacks(name, oldValue, value); + } + }, + + on: function(/*String*/ type, /*Function*/ func){ + // summary: + // Call specified function when event occurs, ex: myWidget.on("click", function(){ ... }). + // description: + // Call specified function when event `type` occurs, ex: `myWidget.on("click", function(){ ... })`. + // Note that the function is not run in any particular scope, so if (for example) you want it to run in the + // widget's scope you must do `myWidget.on("click", lang.hitch(myWidget, func))`. + + return aspect.after(this, this._onMap(type), func, true); + }, + + _onMap: function(/*String*/ type){ + // summary: + // Maps on() type parameter (ex: "mousemove") to method name (ex: "onMouseMove") + var ctor = this.constructor, map = ctor._onMap; + if(!map){ + map = (ctor._onMap = {}); + for(var attr in ctor.prototype){ + if(/^on/.test(attr)){ + map[attr.replace(/^on/, "").toLowerCase()] = attr; + } + } + } + return map[type.toLowerCase()]; // String + }, + + toString: function(){ + // summary: + // Returns a string that represents the widget + // description: + // When a widget is cast to a string, this method will be used to generate the + // output. Currently, it does not implement any sort of reversible + // serialization. + return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String + }, + + getChildren: function(){ + // summary: + // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. + // Does not return nested widgets, nor widgets that are part of this widget's template. + return this.containerNode ? registry.findWidgets(this.containerNode) : []; // dijit._Widget[] + }, + + getParent: function(){ + // summary: + // Returns the parent widget of this widget + return registry.getEnclosingWidget(this.domNode.parentNode); + }, + + connect: function( + /*Object|null*/ obj, + /*String|Function*/ event, + /*String|Function*/ method){ + // summary: + // Connects specified obj/event to specified method of this object + // and registers for disconnect() on widget destroy. + // description: + // Provide widget-specific analog to dojo.connect, except with the + // implicit use of this widget as the target object. + // Events connected with `this.connect` are disconnected upon + // destruction. + // returns: + // A handle that can be passed to `disconnect` in order to disconnect before + // the widget is destroyed. + // example: + // | var btn = new dijit.form.Button(); + // | // when foo.bar() is called, call the listener we're going to + // | // provide in the scope of btn + // | btn.connect(foo, "bar", function(){ + // | console.debug(this.toString()); + // | }); + // tags: + // protected + + var handle = connect.connect(obj, event, this, method); + this._connects.push(handle); + return handle; // _Widget.Handle + }, + + disconnect: function(handle){ + // summary: + // Disconnects handle created by `connect`. + // Also removes handle from this widget's list of connects. + // tags: + // protected + var i = array.indexOf(this._connects, handle); + if(i != -1){ + handle.remove(); + this._connects.splice(i, 1); + } + }, + + subscribe: function(t, method){ + // summary: + // Subscribes to the specified topic and calls the specified method + // of this object and registers for unsubscribe() on widget destroy. + // description: + // Provide widget-specific analog to dojo.subscribe, except with the + // implicit use of this widget as the target object. + // t: String + // The topic + // method: Function + // The callback + // example: + // | var btn = new dijit.form.Button(); + // | // when /my/topic is published, this button changes its label to + // | // be the parameter of the topic. + // | btn.subscribe("/my/topic", function(v){ + // | this.set("label", v); + // | }); + // tags: + // protected + var handle = topic.subscribe(t, lang.hitch(this, method)); + this._connects.push(handle); + return handle; // _Widget.Handle + }, + + unsubscribe: function(/*Object*/ handle){ + // summary: + // Unsubscribes handle created by this.subscribe. + // Also removes handle from this widget's list of subscriptions + // tags: + // protected + this.disconnect(handle); + }, + + isLeftToRight: function(){ + // summary: + // Return this widget's explicit or implicit orientation (true for LTR, false for RTL) + // tags: + // protected + return this.dir ? (this.dir == "ltr") : domGeometry.isBodyLtr(); //Boolean + }, + + isFocusable: function(){ + // summary: + // Return true if this widget can currently be focused + // and false if not + return this.focus && (domStyle.get(this.domNode, "display") != "none"); + }, + + placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){ + // summary: + // Place this widget's domNode reference somewhere in the DOM based + // on standard domConstruct.place conventions, or passing a Widget reference that + // contains and addChild member. + // + // description: + // A convenience function provided in all _Widgets, providing a simple + // shorthand mechanism to put an existing (or newly created) Widget + // somewhere in the dom, and allow chaining. + // + // reference: + // The String id of a domNode, a domNode reference, or a reference to a Widget possessing + // an addChild method. + // + // position: + // If passed a string or domNode reference, the position argument + // accepts a string just as domConstruct.place does, one of: "first", "last", + // "before", or "after". + // + // If passed a _Widget reference, and that widget reference has an ".addChild" method, + // it will be called passing this widget instance into that method, supplying the optional + // position index passed. + // + // returns: + // dijit._Widget + // Provides a useful return of the newly created dijit._Widget instance so you + // can "chain" this function by instantiating, placing, then saving the return value + // to a variable. + // + // example: + // | // create a Button with no srcNodeRef, and place it in the body: + // | var button = new dijit.form.Button({ label:"click" }).placeAt(win.body()); + // | // now, 'button' is still the widget reference to the newly created button + // | button.on("click", function(e){ console.log('click'); })); + // + // example: + // | // create a button out of a node with id="src" and append it to id="wrapper": + // | var button = new dijit.form.Button({},"src").placeAt("wrapper"); + // + // example: + // | // place a new button as the first element of some div + // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first"); + // + // example: + // | // create a contentpane and add it to a TabContainer + // | var tc = dijit.byId("myTabs"); + // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc) + + if(reference.declaredClass && reference.addChild){ + reference.addChild(this, position); + }else{ + domConstruct.place(this.domNode, reference, position); + } + return this; + }, + + getTextDir: function(/*String*/ text,/*String*/ originalDir){ + // summary: + // Return direction of the text. + // The function overridden in the _BidiSupport module, + // its main purpose is to calculate the direction of the + // text, if was defined by the programmer through textDir. + // tags: + // protected. + return originalDir; + }, + + applyTextDir: function(/*===== element, text =====*/){ + // summary: + // The function overridden in the _BidiSupport module, + // originally used for setting element.dir according to this.textDir. + // In this case does nothing. + // element: DOMNode + // text: String + // tags: + // protected. + } +}); + +}); + +}}}); + +require(["dojo/i18n"], function(i18n){ +i18n._preloadLocalizations("dojox/charting/widget/nls/Chart2D", []); +}); +define("dojox/charting/widget/Chart2D", ["dojo/_base/kernel", "./Chart", "../Chart2D", + "../action2d/Highlight", "../action2d/Magnify", + "../action2d/MoveSlice", "../action2d/Shake", "../action2d/Tooltip"], function(dojo, Chart) { + dojo.deprecated("dojox.charting.widget.Chart2D", "Use dojo.charting.widget.Chart instead and require all other components explicitly", "2.0"); + return dojox.charting.widget.Chart2D = Chart; +}); diff --git a/js/dojo-1.7.2/dojox/charting/widget/Legend.js b/js/dojo-1.7.2/dojox/charting/widget/Legend.js new file mode 100644 index 0000000..9bd4732 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/widget/Legend.js @@ -0,0 +1,182 @@ +//>>built +define("dojox/charting/widget/Legend", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/declare", "dijit/_Widget", "dojox/gfx","dojo/_base/array", + "dojox/lang/functional", "dojox/lang/functional/array", "dojox/lang/functional/fold", + "dojo/dom", "dojo/dom-construct", "dojo/dom-class","dijit/_base/manager"], + function(lang, html, declare, Widget, gfx, arrayUtil, df, dfa, dff, + dom, domFactory, domClass, widgetManager){ +/*===== +var Widget = dijit._Widget; +=====*/ + + var REVERSED_SERIES = /\.(StackedColumns|StackedAreas|ClusteredBars)$/; + + return declare("dojox.charting.widget.Legend", Widget, { + // summary: A legend for a chart. A legend contains summary labels for + // each series of data contained in the chart. + // + // Set the horizontal attribute to boolean false to layout legend labels vertically. + // Set the horizontal attribute to a number to layout legend labels in horizontal + // rows each containing that number of labels (except possibly the last row). + // + // (Line or Scatter charts (colored lines with shape symbols) ) + // -o- Series1 -X- Series2 -v- Series3 + // + // (Area/Bar/Pie charts (letters represent colors)) + // [a] Series1 [b] Series2 [c] Series3 + + chartRef: "", + horizontal: true, + swatchSize: 18, + + legendBody: null, + + postCreate: function(){ + if(!this.chart){ + if(!this.chartRef){ return; } + this.chart = widgetManager.byId(this.chartRef); + if(!this.chart){ + var node = dom.byId(this.chartRef); + if(node){ + this.chart = widgetManager.byNode(node); + }else{ + console.log("Could not find chart instance with id: " + this.chartRef); + return; + } + } + this.series = this.chart.chart.series; + }else{ + this.series = this.chart.series; + } + + this.refresh(); + }, + buildRendering: function(){ + this.domNode = domFactory.create("table", + {role: "group", "aria-label": "chart legend", "class": "dojoxLegendNode"}); + this.legendBody = domFactory.create("tbody", null, this.domNode); + this.inherited(arguments); + }, + refresh: function(){ + // summary: regenerates the legend to reflect changes to the chart + + // cleanup + if(this._surfaces){ + arrayUtil.forEach(this._surfaces, function(surface){ + surface.destroy(); + }); + } + this._surfaces = []; + while(this.legendBody.lastChild){ + domFactory.destroy(this.legendBody.lastChild); + } + + if(this.horizontal){ + domClass.add(this.domNode, "dojoxLegendHorizontal"); + // make a container <tr> + this._tr = domFactory.create("tr", null, this.legendBody); + this._inrow = 0; + } + + var s = this.series; + if(s.length == 0){ + return; + } + if(s[0].chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie"){ + var t = s[0].chart.stack[0]; + if(typeof t.run.data[0] == "number"){ + var filteredRun = df.map(t.run.data, "Math.max(x, 0)"); + if(df.every(filteredRun, "<= 0")){ + return; + } + var slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); + arrayUtil.forEach(slices, function(x, i){ + this._addLabel(t.dyn[i], t._getLabel(x * 100) + "%"); + }, this); + }else{ + arrayUtil.forEach(t.run.data, function(x, i){ + this._addLabel(t.dyn[i], x.legend || x.text || x.y); + }, this); + } + }else{ + if(this._isReversal()){ + s = s.slice(0).reverse(); + } + arrayUtil.forEach(s, function(x){ + this._addLabel(x.dyn, x.legend || x.name); + }, this); + } + }, + _addLabel: function(dyn, label){ + // create necessary elements + var wrapper = domFactory.create("td"), + icon = domFactory.create("div", null, wrapper), + text = domFactory.create("label", null, wrapper), + div = domFactory.create("div", { + style: { + "width": this.swatchSize + "px", + "height":this.swatchSize + "px", + "float": "left" + } + }, icon); + domClass.add(icon, "dojoxLegendIcon dijitInline"); + domClass.add(text, "dojoxLegendText"); + // create a skeleton + if(this._tr){ + // horizontal + this._tr.appendChild(wrapper); + if(++this._inrow === this.horizontal){ + // make a fresh container <tr> + this._tr = domFactory.create("tr", null, this.legendBody); + this._inrow = 0; + } + }else{ + // vertical + var tr = domFactory.create("tr", null, this.legendBody); + tr.appendChild(wrapper); + } + + // populate the skeleton + this._makeIcon(div, dyn); + text.innerHTML = String(label); + text.dir = this.getTextDir(label, text.dir); + }, + _makeIcon: function(div, dyn){ + var mb = { h: this.swatchSize, w: this.swatchSize }; + var surface = gfx.createSurface(div, mb.w, mb.h); + this._surfaces.push(surface); + if(dyn.fill){ + // regions + surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}). + setFill(dyn.fill).setStroke(dyn.stroke); + }else if(dyn.stroke || dyn.marker){ + // draw line + var line = {x1: 0, y1: mb.h / 2, x2: mb.w, y2: mb.h / 2}; + if(dyn.stroke){ + surface.createLine(line).setStroke(dyn.stroke); + } + if(dyn.marker){ + // draw marker on top + var c = {x: mb.w / 2, y: mb.h / 2}; + if(dyn.stroke){ + surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}). + setFill(dyn.stroke.color).setStroke(dyn.stroke); + }else{ + surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}). + setFill(dyn.color).setStroke(dyn.color); + } + } + }else{ + // nothing + surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}). + setStroke("black"); + surface.createLine({x1: 2, y1: 2, x2: mb.w - 2, y2: mb.h - 2}).setStroke("black"); + surface.createLine({x1: 2, y1: mb.h - 2, x2: mb.w - 2, y2: 2}).setStroke("black"); + } + }, + _isReversal: function(){ + return (!this.horizontal) && arrayUtil.some(this.chart.stack, function(item){ + return REVERSED_SERIES.test(item.declaredClass); + }); + } + }); +}); diff --git a/js/dojo-1.7.2/dojox/charting/widget/SelectableLegend.js b/js/dojo-1.7.2/dojox/charting/widget/SelectableLegend.js new file mode 100644 index 0000000..2836679 --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/widget/SelectableLegend.js @@ -0,0 +1,245 @@ +//>>built +define("dojox/charting/widget/SelectableLegend", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/query", "dojo/_base/html", + "dojo/_base/connect", "dojo/_base/Color", "./Legend", "dijit/form/CheckBox", "../action2d/Highlight", + "dojox/lang/functional", "dojox/gfx/fx", "dojo/keys", "dojo/_base/event", "dojo/dom-construct", + "dojo/dom-prop"], + function(lang, arrayUtil, declare, query, html, hub, Color, Legend, CheckBox, + Highlight, df, fx, keys, event, dom, domProp){ +/*===== +var Legend = dojox.charting.widget.Legend; +=====*/ + var FocusManager = declare(null, { + // summary: + // It will take legend as a tab stop, and using + // cursor keys to navigate labels within the legend. + constructor: function(legend){ + this.legend = legend; + this.index = 0; + this.horizontalLength = this._getHrizontalLength(); + arrayUtil.forEach(legend.legends, function(item, i){ + if(i > 0){ + query("input", item).attr("tabindex", -1); + } + }); + this.firstLabel = query("input", legend.legends[0])[0]; + hub.connect(this.firstLabel, "focus", this, function(){this.legend.active = true;}); + hub.connect(this.legend.domNode, "keydown", this, "_onKeyEvent"); + }, + _getHrizontalLength: function(){ + var horizontal = this.legend.horizontal; + if(typeof horizontal == "number"){ + return Math.min(horizontal, this.legend.legends.length); + }else if(!horizontal){ + return 1; + }else{ + return this.legend.legends.length; + } + }, + _onKeyEvent: function(e){ + // if not focused + if(!this.legend.active){ + return; + } + // lose focus + if(e.keyCode == keys.TAB){ + this.legend.active = false; + return; + } + // handle with arrow keys + var max = this.legend.legends.length; + switch(e.keyCode){ + case keys.LEFT_ARROW: + this.index--; + if(this.index < 0){ + this.index += max; + } + break; + case keys.RIGHT_ARROW: + this.index++; + if(this.index >= max){ + this.index -= max; + } + break; + case keys.UP_ARROW: + if(this.index - this.horizontalLength >= 0){ + this.index -= this.horizontalLength; + } + break; + case keys.DOWN_ARROW: + if(this.index + this.horizontalLength < max){ + this.index += this.horizontalLength; + } + break; + default: + return; + } + this._moveToFocus(); + Event.stop(e); + }, + _moveToFocus: function(){ + query("input", this.legend.legends[this.index])[0].focus(); + } + }); + + declare("dojox.charting.widget.SelectableLegend", Legend, { + // summary: + // An enhanced chart legend supporting interactive events on data series + + // theme component + outline: false, // outline of vanished data series + transitionFill: null, // fill of deselected data series + transitionStroke: null, // stroke of deselected data series + + postCreate: function(){ + this.legends = []; + this.legendAnim = {}; + this.inherited(arguments); + }, + refresh: function(){ + this.legends = []; + this.inherited(arguments); + this._applyEvents(); + new FocusManager(this); + }, + _addLabel: function(dyn, label){ + this.inherited(arguments); + // create checkbox + var legendNodes = query("td", this.legendBody); + var currentLegendNode = legendNodes[legendNodes.length - 1]; + this.legends.push(currentLegendNode); + var checkbox = new CheckBox({checked: true}); + dom.place(checkbox.domNode, currentLegendNode, "first"); + // connect checkbox and existed label + var label = query("label", currentLegendNode)[0]; + domProp.set(label, "for", checkbox.id); + }, + _applyEvents: function(){ + // summary: + // Apply click-event on checkbox and hover-event on legend icon, + // highlight data series or toggle it. + // if the chart has not yet been refreshed it will crash here (targetData.group == null) + if(this.chart.dirty){ + return; + } + arrayUtil.forEach(this.legends, function(legend, i){ + var targetData, shapes = [], plotName, seriesName; + if(this._isPie()){ + targetData = this.chart.stack[0]; + shapes.push(targetData.group.children[i]); + plotName = targetData.name; + seriesName = this.chart.series[0].name; + }else{ + targetData = this.chart.series[i]; + shapes = targetData.group.children; + plotName = targetData.plot; + seriesName = targetData.name; + } + var originalDyn = { + fills : df.map(shapes, "x.getFill()"), + strokes: df.map(shapes, "x.getStroke()") + }; + // toggle action + var legendCheckBox = query(".dijitCheckBox", legend)[0]; + hub.connect(legendCheckBox, "onclick", this, function(e){ + this._toggle(shapes, i, legend.vanished, originalDyn, seriesName, plotName); + legend.vanished = !legend.vanished; + e.stopPropagation(); + }); + + // highlight action + var legendIcon = query(".dojoxLegendIcon", legend)[0], + iconShape = this._getFilledShape(this._surfaces[i].children); + arrayUtil.forEach(["onmouseenter", "onmouseleave"], function(event){ + hub.connect(legendIcon, event, this, function(e){ + this._highlight(e, iconShape, shapes, i, legend.vanished, originalDyn, seriesName, plotName); + }); + }, this); + },this); + }, + _toggle: function(shapes, index, isOff, dyn, seriesName, plotName){ + arrayUtil.forEach(shapes, function(shape, i){ + var startFill = dyn.fills[i], + endFill = this._getTransitionFill(plotName), + startStroke = dyn.strokes[i], + endStroke = this.transitionStroke; + if(startFill){ + if(endFill && (typeof startFill == "string" || startFill instanceof Color)){ + fx.animateFill({ + shape: shape, + color: { + start: isOff ? endFill : startFill, + end: isOff ? startFill : endFill + } + }).play(); + }else{ + shape.setFill(isOff ? startFill : endFill); + } + } + if(startStroke && !this.outline){ + shape.setStroke(isOff ? startStroke : endStroke); + } + }, this); + }, + _highlight: function(e, iconShape, shapes, index, isOff, dyn, seriesName, plotName){ + if(!isOff){ + var anim = this._getAnim(plotName), + isPie = this._isPie(), + type = formatEventType(e.type); + // highlight the label icon, + var label = { + shape: iconShape, + index: isPie ? "legend" + index : "legend", + run: {name: seriesName}, + type: type + }; + anim.process(label); + // highlight the data items + arrayUtil.forEach(shapes, function(shape, i){ + shape.setFill(dyn.fills[i]); + var o = { + shape: shape, + index: isPie ? index : i, + run: {name: seriesName}, + type: type + }; + anim.duration = 100; + anim.process(o); + }); + } + }, + _getAnim: function(plotName){ + if(!this.legendAnim[plotName]){ + this.legendAnim[plotName] = new Highlight(this.chart, plotName); + } + return this.legendAnim[plotName]; + }, + _getTransitionFill: function(plotName){ + // Since series of stacked charts all start from the base line, + // fill the "front" series with plotarea color to make it disappear . + if(this.chart.stack[this.chart.plots[plotName]].declaredClass.indexOf("dojox.charting.plot2d.Stacked") != -1){ + return this.chart.theme.plotarea.fill; + } + return null; + }, + _getFilledShape: function(shapes){ + // summary: + // Get filled shape in legend icon which would be highlighted when hovered + var i = 0; + while(shapes[i]){ + if(shapes[i].getFill())return shapes[i]; + i++; + } + }, + _isPie: function(){ + return this.chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie"; + } + }); + + function formatEventType(type){ + if(type == "mouseenter")return "onmouseover"; + if(type == "mouseleave")return "onmouseout"; + return "on" + type; + } + + return dojox.charting.widget.SelectableLegend; +}); diff --git a/js/dojo-1.7.2/dojox/charting/widget/Sparkline.js b/js/dojo-1.7.2/dojox/charting/widget/Sparkline.js new file mode 100644 index 0000000..4dbe6ae --- /dev/null +++ b/js/dojo-1.7.2/dojox/charting/widget/Sparkline.js @@ -0,0 +1,59 @@ +//>>built +define("dojox/charting/widget/Sparkline", ["dojo/_base/lang", "dojo/_base/array", "dojo/_base/declare", "dojo/_base/html", "dojo/query", + "./Chart", "../themes/GreySkies", "../plot2d/Lines", "dojo/dom-prop"], + function(lang, arrayUtil, declare, html, query, Chart, GreySkies, Lines, domProp){ +/*===== +var Chart = dojox.charting.widget.Chart; +=====*/ + + declare("dojox.charting.widget.Sparkline", Chart, { + theme: GreySkies, + margins: { l: 0, r: 0, t: 0, b: 0 }, + type: "Lines", + valueFn: "Number(x)", + store: "", + field: "", + query: "", + queryOptions: "", + start: "0", + count: "Infinity", + sort: "", + data: "", + name: "default", + buildRendering: function(){ + var n = this.srcNodeRef; + if( !n.childNodes.length || // shortcut the query + !query("> .axis, > .plot, > .action, > .series", n).length){ + var plot = document.createElement("div"); + domProp.set(plot, { + "class": "plot", + "name": "default", + "type": this.type + }); + n.appendChild(plot); + + var series = document.createElement("div"); + domProp.set(series, { + "class": "series", + plot: "default", + name: this.name, + start: this.start, + count: this.count, + valueFn: this.valueFn + }); + arrayUtil.forEach( + ["store", "field", "query", "queryOptions", "sort", "data"], + function(i){ + if(this[i].length){ + domProp.set(series, i, this[i]); + } + }, + this + ); + n.appendChild(series); + } + this.inherited(arguments); + } + } + ); +}); |
