You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
12 KiB
356 lines
12 KiB
define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/sniff", |
|
"./CartesianBase", "./common", "dojox/lang/utils", "dojox/gfx/fx"], |
|
function(lang, declare, arr, has, CartesianBase, dc, du, fx){ |
|
|
|
var sortTicks = function(a,b){return a.value - b.value}; |
|
|
|
/*===== |
|
declare("dojox.charting.plot2d.__GridCtorArgs", dojox.charting.plot2d.__CartesianCtorArgs, { |
|
// summary: |
|
// A special keyword arguments object that is specific to a grid "plot". |
|
|
|
// majorHLine: dojox.gfx.Stroke? |
|
// An optional dojox.gfx.Stroke for a major horizontal line. By default major lines use major tick stroke. |
|
majorHLine:undefined, |
|
|
|
// minorHLine: dojox.gfx.Stroke? |
|
// An optional dojox.gfx.Stroke for a minor horizontal line. By default minor lines use minor tick stroke. |
|
minorHLine:undefined, |
|
|
|
// majorVLine: dojox.gfx.Stroke? |
|
// An optional dojox.gfx.Stroke for a major vertical line. By default major lines use major tick stroke. |
|
majorVLine:undefined, |
|
|
|
// minorVLine: dojox.gfx.Stroke? |
|
// An optional dojox.gfx.Stroke for a minor vertical line. By default major lines use major tick stroke. |
|
minorVLine:undefined, |
|
|
|
// hFill: dojox.gfx.Fill? |
|
// An optional dojox.gfx.Fill used to fill every other horizontal stripe created by grid lines. |
|
hFill: undefined, |
|
|
|
// hAlternateFill: dojox.gfx.Fill? |
|
// An optional dojox.gfx.Fill used to fill alternating horizontal stripe created by grid lines not filled by `hFill`. |
|
hAlternateFill: undefined, |
|
|
|
// vFill: dojox.gfx.Fill? |
|
// An optional dojox.gfx.Fill used to fill every other vertical stripe created by grid lines. |
|
vFill: undefined, |
|
|
|
// vAlternateFill: dojox.gfx.Fill? |
|
// An optional dojox.gfx.Fill used to fill alternating vertical stripe created by grid lines not filled by `vFill`. |
|
vAlternateFill: undefined, |
|
|
|
// hMajorLines: Boolean? |
|
// Whether to show lines at the major ticks along the horizontal axis. Default is true. |
|
hMajorLines: true, |
|
|
|
// hMinorLines: Boolean? |
|
// Whether to show lines at the minor ticks along the horizontal axis. Default is false. |
|
hMinorLines: false, |
|
|
|
// vMajorLines: Boolean? |
|
// Whether to show lines at the major ticks along the vertical axis. Default is true. |
|
vMajorLines: true, |
|
|
|
// vMinorLines: Boolean? |
|
// Whether to show lines at the major ticks along the vertical axis. Default is false. |
|
vMinorLines: false, |
|
|
|
// hStripes: Boolean? |
|
// Whether to show horizontal stripes. Default is false. |
|
hStripes: false, |
|
|
|
// vStripes: Boolean? |
|
// Whether to show vertical stripes. Default is false. |
|
vStripes: false, |
|
|
|
// enableCache: Boolean? |
|
// Whether the grid lines are cached from one rendering to another. This improves the rendering performance of |
|
// successive rendering but penalize the first rendering. Default false. |
|
enableCache: false, |
|
|
|
// renderOnAxis: Boolean? |
|
// Whether or not the grid is rendered when drawn at horizontal or vertical axis position. Default is true. |
|
renderOnAxis: true |
|
}); |
|
=====*/ |
|
|
|
return declare("dojox.charting.plot2d.Grid", CartesianBase, { |
|
// summary: |
|
// A "faux" plot that can be placed behind other plots to represent |
|
// a grid against which other plots can be easily measured. |
|
defaultParams: { |
|
hMajorLines: true, // draw horizontal major lines |
|
hMinorLines: false, // draw horizontal minor lines |
|
vMajorLines: true, // draw vertical major lines |
|
vMinorLines: false, // draw vertical minor lines |
|
hStripes: false, // draw vertical stripes |
|
vStripes: false, // draw vertical stripes |
|
animate: null, // animate bars into place |
|
enableCache: false, |
|
renderOnAxis: true |
|
}, |
|
|
|
optionalParams: { |
|
majorHLine: {}, |
|
minorHLine: {}, |
|
majorVLine: {}, |
|
minorVLine: {}, |
|
hFill: {}, |
|
vFill: {}, |
|
hAlternateFill: {}, |
|
vAlternateFill: {} |
|
}, |
|
|
|
constructor: function(chart, kwArgs){ |
|
// summary: |
|
// Create the faux Grid plot. |
|
// chart: dojox/charting/Chart |
|
// The chart this plot belongs to. |
|
// kwArgs: dojox.charting.plot2d.__GridCtorArgs? |
|
// An optional keyword arguments object to help define the parameters of the underlying grid. |
|
this.opt = lang.clone(this.defaultParams); |
|
du.updateWithObject(this.opt, kwArgs); |
|
du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
|
this.animate = this.opt.animate; |
|
if(this.opt.enableCache){ |
|
this._lineFreePool = []; |
|
this._lineUsePool = []; |
|
this._rectFreePool = []; |
|
this._rectUsePool = []; |
|
} |
|
}, |
|
addSeries: function(run){ |
|
// summary: |
|
// Ignored but included as a dummy method. |
|
// returns: dojox/charting/plot2d/Grid |
|
// The reference to this plot for functional chaining. |
|
return this; // dojox/charting/plot2d/Grid |
|
}, |
|
getSeriesStats: function(){ |
|
// summary: |
|
// Returns default stats (irrelevant for this type of plot). |
|
// returns: Object |
|
// {hmin, hmax, vmin, vmax} min/max in both directions. |
|
return lang.delegate(dc.defaultStats); // Object |
|
}, |
|
cleanGroup: function(){ |
|
this.inherited(arguments); |
|
if(this.opt.enableCache){ |
|
this._lineFreePool = this._lineFreePool.concat(this._lineUsePool); |
|
this._lineUsePool = []; |
|
this._rectFreePool = this._rectFreePool.concat(this._rectUsePool); |
|
this._rectUsePool = []; |
|
} |
|
}, |
|
createLine: function(creator, params){ |
|
var line; |
|
if(this.opt.enableCache && this._lineFreePool.length > 0){ |
|
line = this._lineFreePool.pop(); |
|
line.setShape(params); |
|
// was cleared, add it back |
|
creator.add(line); |
|
}else{ |
|
line = creator.createLine(params); |
|
} |
|
if(this.opt.enableCache){ |
|
this._lineUsePool.push(line); |
|
} |
|
return line; |
|
}, |
|
createRect: function(creator, params){ |
|
var rect; |
|
if(this.opt.enableCache && this._rectFreePool.length > 0){ |
|
rect = this._rectFreePool.pop(); |
|
rect.setShape(params); |
|
// was cleared, add it back |
|
creator.add(rect); |
|
}else{ |
|
rect = creator.createRect(params); |
|
} |
|
if(this.opt.enableCache){ |
|
this._rectUsePool.push(rect); |
|
} |
|
return rect; |
|
}, |
|
|
|
render: function(dim, offsets){ |
|
// summary: |
|
// Render the plot on the chart. |
|
// dim: Object |
|
// An object of the form { width, height }. |
|
// offsets: Object |
|
// An object of the form { l, r, t, b }. |
|
// returns: dojox/charting/plot2d/Grid |
|
// A reference to this plot for functional chaining. |
|
if(this.zoom){ |
|
return this.performZoom(dim, offsets); |
|
} |
|
this.dirty = this.isDirty(); |
|
if(!this.dirty){ return this; } |
|
this.cleanGroup(); |
|
var s = this.getGroup(), ta = this.chart.theme, lineStroke, ticks; |
|
if((has("ios") && has("ios") < 6) || has("android") || (has("safari") && !has("ios"))){ |
|
// clipping seems buggy in some mobile Webkit browser and Safari desktop |
|
// it does not clip correctly if only lines are present => create a invisible rectangle... |
|
var w = Math.max(0, dim.width - offsets.l - offsets.r), |
|
h = Math.max(0, dim.height - offsets.t - offsets.b); |
|
s.createRect({ x: offsets.l, y: offsets.t, width: w, height: h}); |
|
} |
|
if(this._vAxis){ |
|
// draw horizontal stripes and lines |
|
ticks = this._vAxis.getTicks(); |
|
var vScaler = this._vAxis.getScaler(); |
|
if(ticks != null && vScaler != null){ |
|
var vt = vScaler.scaler.getTransformerFromModel(vScaler); |
|
if(this.opt.hStripes){ |
|
this._renderHRect(ticks, ta.grid, dim, offsets, vScaler, vt); |
|
} |
|
if(this.opt.hMinorLines){ |
|
lineStroke = this.opt.minorHLine || (ta.grid && ta.grid.minorLine) || ta.axis.minorTick; |
|
this._renderHLines(ticks.minor, lineStroke, dim, offsets, vScaler, vt); |
|
} |
|
if(this.opt.hMajorLines){ |
|
lineStroke = this.opt.majorHLine || (ta.grid && ta.grid.majorLine) || ta.axis.majorTick; |
|
this._renderHLines(ticks.major, lineStroke, dim, offsets, vScaler, vt); |
|
} |
|
} |
|
|
|
} |
|
if(this._hAxis){ |
|
// draw vertical stripes and lines |
|
ticks = this._hAxis.getTicks(); |
|
var hScaler = this._hAxis.getScaler(); |
|
if(ticks != null && hScaler != null){ |
|
var ht = hScaler.scaler.getTransformerFromModel(hScaler); |
|
if(this.opt.vStripes){ |
|
this._renderVRect(ticks, ta.grid, dim, offsets, hScaler, ht); |
|
} |
|
if(ticks && this.opt.vMinorLines){ |
|
lineStroke = this.opt.minorVLine || (ta.grid && ta.grid.minorLine) || ta.axis.minorTick; |
|
this._renderVLines(ticks.minor, lineStroke, dim, offsets, hScaler, ht); |
|
} |
|
if(ticks && this.opt.vMajorLines){ |
|
lineStroke = this.opt.majorVLine || (ta.grid && ta.grid.majorLine) || ta.axis.majorTick; |
|
this._renderVLines(ticks.major, lineStroke, dim, offsets, hScaler, ht); |
|
} |
|
|
|
} |
|
} |
|
this.dirty = false; |
|
return this; // dojox/charting/plot2d/Grid |
|
}, |
|
_renderHLines: function(ticks, lineStroke, dim, offsets, vScaler, vt){ |
|
var s = this.getGroup(); |
|
arr.forEach(ticks, function(tick){ |
|
if(!this.opt.renderOnAxis && tick.value == (this._vAxis.opt.leftBottom?vScaler.bounds.from:vScaler.bounds.to)){ |
|
return; |
|
} |
|
var y = dim.height - offsets.b - vt(tick.value); |
|
var hLine = this.createLine(s, { |
|
x1: offsets.l, |
|
y1: y, |
|
x2: dim.width - offsets.r, |
|
y2: y |
|
}).setStroke(lineStroke); |
|
if(this.animate){ |
|
this._animateGrid(hLine, "h", offsets.l, offsets.r + offsets.l - dim.width); |
|
} |
|
}, this); |
|
}, |
|
_renderVLines: function(ticks, lineStroke, dim, offsets, hScaler, ht){ |
|
var s = this.getGroup(); |
|
arr.forEach(ticks, function(tick){ |
|
if(!this.opt.renderOnAxis && tick.value == (this._hAxis.opt.leftBottom?hScaler.bounds.from:hScaler.bounds.to)){ |
|
return; |
|
} |
|
var x = offsets.l + ht(tick.value); |
|
var vLine = this.createLine(s, { |
|
x1: x, |
|
y1: offsets.t, |
|
x2: x, |
|
y2: dim.height - offsets.b |
|
}).setStroke(lineStroke); |
|
if(this.animate){ |
|
this._animateGrid(vLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); |
|
} |
|
}, this); |
|
}, |
|
_renderHRect: function(ticks, theme, dim, offsets, vScaler, vt){ |
|
var fill, tick, y, y2, hStripe; |
|
var allTicks = ticks.major.concat(ticks.minor); |
|
allTicks.sort(sortTicks); |
|
if(allTicks[0].value > vScaler.bounds.from){ |
|
allTicks.splice(0, 0, {value: vScaler.bounds.from}); |
|
} |
|
if(allTicks[allTicks.length - 1].value < vScaler.bounds.to){ |
|
allTicks.push({value: vScaler.bounds.to}); |
|
} |
|
var s = this.getGroup(); |
|
for(var j = 0; j < allTicks.length - 1; j++){ |
|
tick = allTicks[j]; |
|
y = dim.height - offsets.b - vt(tick.value); |
|
y2 = dim.height - offsets.b - vt(allTicks[j+1].value); |
|
|
|
fill = (j%2 == 0)?(this.opt.hAlternateFill ||(theme && theme.alternateFill)): |
|
(this.opt.hFill || (theme && theme.fill)); |
|
if(fill){ |
|
hStripe = this.createRect(s, { |
|
x: offsets.l, |
|
y: y, |
|
width: dim.width - offsets.r, |
|
height: y - y2 |
|
}).setFill(fill); |
|
if(this.animate){ |
|
this._animateGrid(hStripe, "h", offsets.l, offsets.r + offsets.l - dim.width); |
|
} |
|
} |
|
} |
|
}, |
|
_renderVRect: function(ticks, theme, dim, offsets, hScaler, ht){ |
|
var fill, tick, x, x2, vStripe; |
|
var allTicks = ticks.major.concat(ticks.minor); |
|
allTicks.sort(sortTicks); |
|
if(allTicks[0].value > hScaler.bounds.from){ |
|
allTicks.splice(0, 0, {value: hScaler.bounds.from}); |
|
} |
|
if(allTicks[allTicks.length - 1].value < hScaler.bounds.to){ |
|
allTicks.push({value: hScaler.bounds.to}); |
|
} |
|
var s = this.getGroup(); |
|
for(var j = 0; j < allTicks.length - 1; j++){ |
|
tick = allTicks[j]; |
|
x = offsets.l + ht(tick.value); |
|
x2 = offsets.l + ht(allTicks[j+1].value); |
|
|
|
fill = (j%2 == 0)?(this.opt.vAlternateFill ||(theme && theme.alternateFill)): |
|
(this.opt.vFill || (theme && theme.fill)); |
|
if(fill){ |
|
vStripe = this.createRect(s, { |
|
x: x, |
|
y: offsets.t, |
|
width: x2 - x, |
|
height: dim.width - offsets.r |
|
}).setFill(fill); |
|
if(this.animate){ |
|
this._animateGrid(vStripe, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t); |
|
} |
|
} |
|
} |
|
}, |
|
_animateGrid: function(shape, type, offset, size){ |
|
var transStart = type == "h" ? [offset, 0] : [0, offset]; |
|
var scaleStart = type == "h" ? [1/size, 1] : [1, 1/size]; |
|
fx.animateTransform(lang.delegate({ |
|
shape: shape, |
|
duration: 1200, |
|
transform: [ |
|
{name: "translate", start: transStart, end: [0, 0]}, |
|
{name: "scale", start: scaleStart, end: [1, 1]}, |
|
{name: "original"} |
|
] |
|
}, this.animate)).play(); |
|
} |
|
}); |
|
});
|
|
|