define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/has", "./Base", "../scaler/primitive", "dojox/gfx", "dojox/gfx/fx", "dojox/lang/utils"], function(lang, declare, hub, has, Base, primitive, gfx, fx, du){ /*===== declare("dojox.charting.plot2d.__CartesianCtorArgs", dojox.charting.plot2d.__PlotCtorArgs, { // hAxis: String? // The horizontal axis name. hAxis: "x", // vAxis: String? // The vertical axis name vAxis: "y", // labels: Boolean? // For plots that support labels, whether or not to draw labels for each data item. Default is false. labels: false, // fixed: Boolean? // Whether a fixed precision must be applied to data values for display. Default is true. fixed: true, // precision: Number? // The precision at which to round data values for display. Default is 0. precision: 1, // labelOffset: Number? // The amount in pixels by which to offset labels when using "outside" labelStyle. Default is 10. labelOffset: 10, // labelStyle: String? // Options as to where to draw labels. This must be either "inside" or "outside". By default // the labels are drawn "inside" the shape representing the data point (a column rectangle for a Columns plot // or a marker for a Line plot for instance). When "outside" is used the labels are drawn above the data point shape. labelStyle: "inside", // htmlLabels: Boolean? // Whether or not to use HTML to render slice labels. Default is true. htmlLabels: true, // omitLabels: Boolean? // Whether labels that do not fit in an item render are omitted or not. This applies only when labelStyle // is "inside". Default is false. omitLabels: true, // labelFunc: Function? // An optional function to use to compute label text. It takes precedence over // the default text when available. // | function labelFunc(value, fixed, precision) {} // `value` is the data value to display // `fixed` is true if fixed precision must be applied. // `precision` is the requested precision to be applied. labelFunc: null }); =====*/ return declare("dojox.charting.plot2d.CartesianBase", Base, { baseParams: { hAxis: "x", vAxis: "y", labels: false, labelOffset: 10, fixed: true, precision: 1, labelStyle: "inside", htmlLabels: true, // use HTML to draw labels omitLabels: true, labelFunc: null }, // summary: // Base class for cartesian plot types. constructor: function(chart, kwArgs){ // summary: // Create a cartesian base plot for cartesian charts. // chart: dojox/chart/Chart // The chart this plot belongs to. // kwArgs: dojox.charting.plot2d.__CartesianCtorArgs? // An optional arguments object to help define the plot. this.axes = ["hAxis", "vAxis"]; this.zoom = null; this.zoomQueue = []; // zooming action task queue this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0}; this.hAxis = (kwArgs && kwArgs.hAxis) || "x"; this.vAxis = (kwArgs && kwArgs.vAxis) || "y"; this.series = []; this.opt = lang.clone(this.baseParams); du.updateWithObject(this.opt, kwArgs); }, clear: function(){ // summary: // Clear out all of the information tied to this plot. // returns: dojox/charting/plot2d/CartesianBase // A reference to this plot for functional chaining. this.inherited(arguments); this._hAxis = null; this._vAxis = null; return this; // dojox/charting/plot2d/CartesianBase }, cleanGroup: function(creator, noClip){ this.inherited(arguments); if(!noClip && this.chart._nativeClip){ var offsets = this.chart.offsets, dim = this.chart.dim; var w = Math.max(0, dim.width - offsets.l - offsets.r), h = Math.max(0, dim.height - offsets.t - offsets.b); this.group.setClip({ x: offsets.l, y: offsets.t, width: w, height: h }); if(!this._clippedGroup){ this._clippedGroup = this.group.createGroup(); } } }, purgeGroup: function(){ this.inherited(arguments); this._clippedGroup = null; }, getGroup: function(){ return this._clippedGroup || this.group; }, setAxis: function(axis){ // summary: // Set an axis for this plot. // axis: dojox/charting/axis2d/Base // The axis to set. // returns: dojox/charting/plot2d/CartesianBase // A reference to this plot for functional chaining. if(axis){ this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; } return this; // dojox/charting/plot2d/CartesianBase }, toPage: function(coord){ // summary: // Compute page coordinates from plot axis data coordinates. // coord: Object? // The coordinates in plot axis data coordinate space. For cartesian charts that is of the following form: // `{ hAxisName: 50, vAxisName: 200 }` // If not provided return the transform method instead of the result of the transformation. // returns: Object // The resulting page pixel coordinates. That is of the following form: // `{ x: 50, y: 200 }` var ah = this._hAxis, av = this._vAxis, sh = ah.getScaler(), sv = av.getScaler(), th = sh.scaler.getTransformerFromModel(sh), tv = sv.scaler.getTransformerFromModel(sv), c = this.chart.getCoords(), o = this.chart.offsets, dim = this.chart.dim; var t = function(coord){ var r = {}; r.x = th(coord[ah.name]) + c.x + o.l; r.y = c.y + dim.height - o.b - tv(coord[av.name]); return r; }; // if no coord return the function so that we can capture the current transforms // and reuse them later on return coord?t(coord):t; // Object }, toData: function(coord){ // summary: // Compute plot axis data coordinates from page coordinates. // coord: Object // The pixel coordinate in page coordinate space. That is of the following form: // `{ x: 50, y: 200 }` // If not provided return the tranform method instead of the result of the transformation. // returns: Object // The resulting plot axis data coordinates. For cartesian charts that is of the following form: // `{ hAxisName: 50, vAxisName: 200 }` var ah = this._hAxis, av = this._vAxis, sh = ah.getScaler(), sv = av.getScaler(), th = sh.scaler.getTransformerFromPlot(sh), tv = sv.scaler.getTransformerFromPlot(sv), c = this.chart.getCoords(), o = this.chart.offsets, dim = this.chart.dim; var t = function(coord){ var r = {}; r[ah.name] = th(coord.x - c.x - o.l); r[av.name] = tv(c.y + dim.height - coord.y - o.b); return r; }; // if no coord return the function so that we can capture the current transforms // and reuse them later on return coord?t(coord):t; // Object }, isDirty: function(){ // summary: // Returns whether or not this plot needs to be rendered. // returns: Boolean // The state of the plot. return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean }, createLabel: function(group, value, bbox, theme){ if(this.opt.labels){ var x, y, label = this.opt.labelFunc?this.opt.labelFunc.apply(this, [value, this.opt.fixed, this.opt.precision]): this._getLabel(isNaN(value.y)?value:value.y); if(this.opt.labelStyle == "inside"){ var lbox = gfx._base._getTextBox(label, { font: theme.series.font } ); x = bbox.x + bbox.width / 2; y = bbox.y + bbox.height / 2 + lbox.h / 4; if(lbox.w > bbox.width || lbox.h > bbox.height){ return; } }else{ x = bbox.x + bbox.width / 2; y = bbox.y - this.opt.labelOffset; } this.renderLabel(group, x, y, label, theme, this.opt.labelStyle == "inside"); } }, performZoom: function(dim, offsets){ // summary: // Create/alter any zooming windows on this plot. // dim: Object // An object of the form { width, height }. // offsets: Object // An object of the form { l, r, t, b }. // returns: dojox/charting/plot2d/CartesianBase // A reference to this plot for functional chaining. // get current zooming various var vs = this._vAxis.scale || 1, hs = this._hAxis.scale || 1, vOffset = dim.height - offsets.b, hBounds = this._hScaler.bounds, xOffset = (hBounds.from - hBounds.lower) * hBounds.scale, vBounds = this._vScaler.bounds, yOffset = (vBounds.from - vBounds.lower) * vBounds.scale, // get incremental zooming various rVScale = vs / this.lastWindow.vscale, rHScale = hs / this.lastWindow.hscale, rXOffset = (this.lastWindow.xoffset - xOffset)/ ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale), rYOffset = (yOffset - this.lastWindow.yoffset)/ ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale), shape = this.getGroup(), anim = fx.animateTransform(lang.delegate({ shape: shape, duration: 1200, transform:[ {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]}, {name:"scale", start:[1, 1], end: [rHScale, rVScale]}, {name:"original"}, {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]} ]}, this.zoom)); lang.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset}); //add anim to zooming action queue, //in order to avoid several zooming action happened at the same time this.zoomQueue.push(anim); //perform each anim one by one in zoomQueue hub.connect(anim, "onEnd", this, function(){ this.zoom = null; this.zoomQueue.shift(); if(this.zoomQueue.length > 0){ this.zoomQueue[0].play(); } }); if(this.zoomQueue.length == 1){ this.zoomQueue[0].play(); } return this; // dojox/charting/plot2d/CartesianBase }, initializeScalers: function(dim, stats){ // summary: // Initializes scalers using attached axes. // dim: Object // Size of a plot area in pixels as {width, height}. // stats: Object // Min/max of data in both directions as {hmin, hmax, vmin, vmax}. // returns: dojox/charting/plot2d/CartesianBase // A reference to this plot for functional chaining. if(this._hAxis){ if(!this._hAxis.initialized()){ this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); } this._hScaler = this._hAxis.getScaler(); }else{ this._hScaler = primitive.buildScaler(stats.hmin, stats.hmax, dim.width); } if(this._vAxis){ if(!this._vAxis.initialized()){ this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); } this._vScaler = this._vAxis.getScaler(); }else{ this._vScaler = primitive.buildScaler(stats.vmin, stats.vmax, dim.height); } return this; // dojox/charting/plot2d/CartesianBase } }); });