i4way-dash/.svn/pristine/28/28dd581843e6400b594240bcc8a...

433 lines
15 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* @file Data zoom model
*/
define(function(require) {
var zrUtil = require('zrender/core/util');
var env = require('zrender/core/env');
var echarts = require('../../echarts');
var modelUtil = require('../../util/model');
var AxisProxy = require('./AxisProxy');
var each = zrUtil.each;
var eachAxisDim = modelUtil.eachAxisDim;
var DataZoomModel = echarts.extendComponentModel({
type: 'dataZoom',
dependencies: [
'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'series'
],
/**
* @protected
*/
defaultOption: {
zlevel: 0,
z: 4, // Higher than normal component (z: 2).
orient: null, // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.
xAxisIndex: null, // Default all horizontal category axis.
yAxisIndex: null, // Default all vertical category axis.
angleAxisIndex: null,
radiusAxisIndex: null,
filterMode: 'filter', // Possible values: 'filter' or 'empty'.
// 'filter': data items which are out of window will be removed.
// This option is applicable when filtering outliers.
// 'empty': data items which are out of window will be set to empty.
// This option is applicable when user should not neglect
// that there are some data items out of window.
// Taking line chart as an example, line will be broken in
// the filtered points when filterModel is set to 'empty', but
// be connected when set to 'filter'.
throttle: 100, // Dispatch action by the fixed rate, avoid frequency.
// default 100. Do not throttle when use null/undefined.
start: 0, // Start percent. 0 ~ 100
end: 100, // End percent. 0 ~ 100
startValue: null, // Start value. If startValue specified, start is ignored.
endValue: null // End value. If endValue specified, end is ignored.
},
/**
* @override
*/
init: function (option, parentModel, ecModel) {
/**
* key like x_0, y_1
* @private
* @type {Object}
*/
this._dataIntervalByAxis = {};
/**
* @private
*/
this._dataInfo = {};
/**
* key like x_0, y_1
* @private
*/
this._axisProxies = {};
/**
* @readOnly
*/
this.textStyleModel;
var rawOption = retrieveRaw(option);
this.mergeDefaultAndTheme(option, ecModel);
this.doInit(rawOption);
},
/**
* @override
*/
mergeOption: function (newOption) {
var rawOption = retrieveRaw(newOption);
//FIX #2591
zrUtil.merge(this.option, newOption, true);
this.doInit(rawOption);
},
/**
* @protected
*/
doInit: function (rawOption) {
var thisOption = this.option;
// Disable realtime view update if canvas is not supported.
if (!env.canvasSupported) {
thisOption.realtime = false;
}
processRangeProp('start', 'startValue', rawOption, thisOption);
processRangeProp('end', 'endValue', rawOption, thisOption);
this.textStyleModel = this.getModel('textStyle');
this._resetTarget();
this._giveAxisProxies();
},
/**
* @private
*/
_giveAxisProxies: function () {
var axisProxies = this._axisProxies;
this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {
var axisModel = this.dependentModels[dimNames.axis][axisIndex];
// If exists, share axisProxy with other dataZoomModels.
var axisProxy = axisModel.__dzAxisProxy || (
// Use the first dataZoomModel as the main model of axisProxy.
axisModel.__dzAxisProxy = new AxisProxy(
dimNames.name, axisIndex, this, ecModel
)
);
// FIXME
// dispose __dzAxisProxy
axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;
}, this);
},
/**
* @private
*/
_resetTarget: function () {
var thisOption = this.option;
var autoMode = this._judgeAutoMode();
eachAxisDim(function (dimNames) {
var axisIndexName = dimNames.axisIndex;
thisOption[axisIndexName] = modelUtil.normalizeToArray(
thisOption[axisIndexName]
);
}, this);
if (autoMode === 'axisIndex') {
this._autoSetAxisIndex();
}
else if (autoMode === 'orient') {
this._autoSetOrient();
}
},
/**
* @private
*/
_judgeAutoMode: function () {
// Auto set only works for setOption at the first time.
// The following is user's reponsibility. So using merged
// option is OK.
var thisOption = this.option;
var hasIndexSpecified = false;
eachAxisDim(function (dimNames) {
// When user set axisIndex as a empty array, we think that user specify axisIndex
// but do not want use auto mode. Because empty array may be encountered when
// some error occured.
if (thisOption[dimNames.axisIndex] != null) {
hasIndexSpecified = true;
}
}, this);
var orient = thisOption.orient;
if (orient == null && hasIndexSpecified) {
return 'orient';
}
else if (!hasIndexSpecified) {
if (orient == null) {
thisOption.orient = 'horizontal';
}
return 'axisIndex';
}
},
/**
* @private
*/
_autoSetAxisIndex: function () {
var autoAxisIndex = true;
var orient = this.get('orient', true);
var thisOption = this.option;
if (autoAxisIndex) {
// Find axis that parallel to dataZoom as default.
var dimNames = orient === 'vertical'
? {dim: 'y', axisIndex: 'yAxisIndex', axis: 'yAxis'}
: {dim: 'x', axisIndex: 'xAxisIndex', axis: 'xAxis'};
if (this.dependentModels[dimNames.axis].length) {
thisOption[dimNames.axisIndex] = [0];
autoAxisIndex = false;
}
}
if (autoAxisIndex) {
// Find the first category axis as default. (consider polar)
eachAxisDim(function (dimNames) {
if (!autoAxisIndex) {
return;
}
var axisIndices = [];
var axisModels = this.dependentModels[dimNames.axis];
if (axisModels.length && !axisIndices.length) {
for (var i = 0, len = axisModels.length; i < len; i++) {
if (axisModels[i].get('type') === 'category') {
axisIndices.push(i);
}
}
}
thisOption[dimNames.axisIndex] = axisIndices;
if (axisIndices.length) {
autoAxisIndex = false;
}
}, this);
}
if (autoAxisIndex) {
// FIXME
// 这里是兼容ec2的写法没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制
// 但是实际是否需要Grid.js#getScaleByOption来判断考虑timelog等axis type
// If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,
// dataZoom component auto adopts series that reference to
// both xAxis and yAxis which type is 'value'.
this.ecModel.eachSeries(function (seriesModel) {
if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {
eachAxisDim(function (dimNames) {
var axisIndices = thisOption[dimNames.axisIndex];
var axisIndex = seriesModel.get(dimNames.axisIndex);
if (zrUtil.indexOf(axisIndices, axisIndex) < 0) {
axisIndices.push(axisIndex);
}
});
}
}, this);
}
},
/**
* @private
*/
_autoSetOrient: function () {
var dim;
// Find the first axis
this.eachTargetAxis(function (dimNames) {
!dim && (dim = dimNames.name);
}, this);
this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';
},
/**
* @private
*/
_isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {
// FIXME
// 需要series的xAxisIndex和yAxisIndex都首先自动设置上。
// 例如series.type === scatter时。
var is = true;
eachAxisDim(function (dimNames) {
var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);
var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];
if (!axisModel || axisModel.get('type') !== axisType) {
is = false;
}
}, this);
return is;
},
/**
* @public
*/
getFirstTargetAxisModel: function () {
var firstAxisModel;
eachAxisDim(function (dimNames) {
if (firstAxisModel == null) {
var indices = this.get(dimNames.axisIndex);
if (indices.length) {
firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];
}
}
}, this);
return firstAxisModel;
},
/**
* @public
* @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel
*/
eachTargetAxis: function (callback, context) {
var ecModel = this.ecModel;
eachAxisDim(function (dimNames) {
each(
this.get(dimNames.axisIndex),
function (axisIndex) {
callback.call(context, dimNames, axisIndex, this, ecModel);
},
this
);
}, this);
},
getAxisProxy: function (dimName, axisIndex) {
return this._axisProxies[dimName + '_' + axisIndex];
},
/**
* If not specified, set to undefined.
*
* @public
* @param {Object} opt
* @param {number} [opt.start]
* @param {number} [opt.end]
* @param {number} [opt.startValue]
* @param {number} [opt.endValue]
*/
setRawRange: function (opt) {
each(['start', 'end', 'startValue', 'endValue'], function (name) {
// If any of those prop is null/undefined, we should alos set
// them, because only one pair between start/end and
// startValue/endValue can work.
this.option[name] = opt[name];
}, this);
},
/**
* @public
* @return {Array.<number>} [startPercent, endPercent]
*/
getPercentRange: function () {
var axisProxy = this.findRepresentativeAxisProxy();
if (axisProxy) {
return axisProxy.getDataPercentWindow();
}
},
/**
* @public
* For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);
*
* @param {string} [axisDimName]
* @param {number} [axisIndex]
* @return {Array.<number>} [startValue, endValue]
*/
getValueRange: function (axisDimName, axisIndex) {
if (axisDimName == null && axisIndex == null) {
var axisProxy = this.findRepresentativeAxisProxy();
if (axisProxy) {
return axisProxy.getDataValueWindow();
}
}
else {
return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();
}
},
/**
* @public
* @return {module:echarts/component/dataZoom/AxisProxy}
*/
findRepresentativeAxisProxy: function () {
// Find the first hosted axisProxy
var axisProxies = this._axisProxies;
for (var key in axisProxies) {
if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {
return axisProxies[key];
}
}
// If no hosted axis find not hosted axisProxy.
// Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,
// and the option.start or option.end settings are different. The percentRange
// should follow axisProxy.
// (We encounter this problem in toolbox data zoom.)
for (var key in axisProxies) {
if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {
return axisProxies[key];
}
}
}
});
function retrieveRaw(option) {
var ret = {};
each(
['start', 'end', 'startValue', 'endValue'],
function (name) {
ret[name] = option[name];
}
);
return ret;
}
function processRangeProp(percentProp, valueProp, rawOption, thisOption) {
// start/end has higher priority over startValue/endValue,
// but we should make chart.setOption({endValue: 1000}) effective,
// rather than chart.setOption({endValue: 1000, end: null}).
if (rawOption[valueProp] != null && rawOption[percentProp] == null) {
thisOption[percentProp] = null;
}
// Otherwise do nothing and use the merge result.
}
return DataZoomModel;
});