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