/* 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 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("
"); 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 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 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= 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= 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="