提交 3ac53726 编写于 作者: P pah100

visual map destructure

上级 d9473b24
......@@ -3,14 +3,14 @@
*/
define(function(require) {
var VisualMapModel = require('./VisualMapModel');
var ControllerModel = require('./ControllerModel');
var zrUtil = require('zrender/core/util');
var numberUtil = require('../../util/number');
// Constant
var DEFAULT_BAR_BOUND = [20, 140];
var ContinuousModel = VisualMapModel.extend({
var ContinuousModel = ControllerModel.extend({
type: 'visualMap.continuous',
......@@ -35,15 +35,19 @@ define(function(require) {
/**
* @override
*/
doMergeOption: function (newOption, isInit) {
ContinuousModel.superApply(this, 'doMergeOption', arguments);
optionUpdated: function (newOption, isInit) {
ContinuousModel.superApply(this, 'optionUpdated', arguments);
this.resetTargetSeries(newOption, isInit);
this.resetTargetSeries();
this.resetExtent();
this.resetVisual(function (mappingOption) {
this.resetVisual('controller', this.controllerVisuals, fillVisualOption);
this.resetVisual('target', this.targetVisuals, fillVisualOption);
function fillVisualOption(mappingOption) {
mappingOption.mappingMethod = 'linear';
});
mappingOption.dataExtent = this.getExtent();
}
this._resetRange();
},
......@@ -53,7 +57,7 @@ define(function(require) {
* @override
*/
resetItemSize: function () {
VisualMapModel.prototype.resetItemSize.apply(this, arguments);
ContinuousModel.superApply(this, 'resetItemSize', arguments);
var itemSize = this.itemSize;
......@@ -90,7 +94,7 @@ define(function(require) {
* @override
*/
completeVisualOption: function () {
VisualMapModel.prototype.completeVisualOption.apply(this, arguments);
ControllerModel.prototype.completeVisualOption.apply(this, arguments);
zrUtil.each(this.stateList, function (state) {
var symbolSize = this.option.controller[state].symbolSize;
......@@ -160,7 +164,7 @@ define(function(require) {
range[0] <= value && value <= range[1] && dataIndices.push(dataIndex);
}, true, this);
result.push({seriesId: seriesModel.id, dataIndices: dataIndices});
result.push({seriesId: seriesModel.id, dataIndex: dataIndices});
}, this);
return result;
......
define(function(require) {
var VisualMapView = require('./VisualMapView');
var ControllerView = require('./ControllerView');
var graphic = require('../../util/graphic');
var zrUtil = require('zrender/core/util');
var numberUtil = require('../../util/number');
......@@ -10,7 +10,6 @@ define(function(require) {
var modelUtil = require('../../util/model');
var linearMap = numberUtil.linearMap;
var convertDataIndicesToBatch = helper.convertDataIndicesToBatch;
var each = zrUtil.each;
var mathMin = Math.min;
var mathMax = Math.max;
......@@ -27,7 +26,7 @@ define(function(require) {
// high data value: this._dataInterval[1] and has high coord.
// The logic of transform is implemented in this._createBarGroup.
var ContinuousVisualMapView = VisualMapView.extend({
var ContinuousView = ControllerView.extend({
type: 'visualMap.continuous',
......@@ -36,7 +35,7 @@ define(function(require) {
*/
init: function () {
VisualMapView.prototype.init.apply(this, arguments);
ContinuousView.superApply(this, 'init', arguments);
/**
* @private
......@@ -677,16 +676,13 @@ define(function(require) {
// When realtime is set as true, highlight will not show when hover
// handle, because the label on handle, which displays a exact value
// but not range, might mislead users.
var oldBatch = convertDataIndicesToBatch(this._hoverLinkDataIndices);
var oldBatch = this._hoverLinkDataIndices;
var newBatch = [];
if (hoverOnBar || useHoverLinkOnHandle(visualMapModel)) {
this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange);
newBatch = convertDataIndicesToBatch(this._hoverLinkDataIndices);
newBatch = this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange);
}
var resultBatches = modelUtil.removeDuplicate(oldBatch, newBatch, function (item) {
return item.seriesIndex + '-' + item.dataIndex;
});
var resultBatches = modelUtil.compressBatches(oldBatch, newBatch);
this._dispatchHighDown('downplay', resultBatches[0]);
this._dispatchHighDown('highlight', resultBatches[1]);
},
......@@ -726,7 +722,7 @@ define(function(require) {
var indices = this._hoverLinkDataIndices;
this._dispatchHighDown('downplay', convertDataIndicesToBatch(indices));
this._dispatchHighDown('downplay', indices);
indices.length = 0;
},
......@@ -822,5 +818,5 @@ define(function(require) {
return !visualMapModel.get('realtime') && visualMapModel.get('hoverLinkOnHandle');
}
return ContinuousVisualMapView;
return ContinuousView;
});
/**
* @file Controller visual map model
*/
define(function(require) {
var zrUtil = require('zrender/core/util');
var VisualMapModel = require('./VisualMapModel');
var visualDefault = require('../../visual/visualDefault');
var VisualMapping = require('../../visual/VisualMapping');
var mapVisual = VisualMapping.mapVisual;
var eachVisual = VisualMapping.eachVisual;
var numberUtil = require('../../util/number');
var isArray = zrUtil.isArray;
var each = zrUtil.each;
var asc = numberUtil.asc;
var linearMap = numberUtil.linearMap;
var ControllerModel = VisualMapModel.extend({
/**
* [lowerBound, upperBound]
*
* @readOnly
* @type {Array.<number>}
*/
dataBound: [-Infinity, Infinity],
/**
* @readOnly
* @type {Array.<string>}
*/
stateList: ['inRange', 'outOfRange'],
/**
* @readOnly
* @type {Array.<string>}
*/
replacableOptionKeys: [
'inRange', 'outOfRange', 'target', 'controller', 'color'
],
/**
* @readOnly
* @type {string|Object}
*/
layoutMode: {type: 'box', ignoreSize: true},
/**
* @protected
*/
defaultOption: {
show: true,
zlevel: 0,
z: 4,
// set min: 0, max: 200, only for campatible with ec2.
// In fact min max should not have default value.
min: 0, // min value, must specified if pieces is not specified.
max: 200, // max value, must specified if pieces is not specified.
dimension: null,
inRange: null, // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha',
// 'symbol', 'symbolSize'
outOfRange: null, // 'color', 'colorHue', 'colorSaturation',
// 'colorLightness', 'colorAlpha',
// 'symbol', 'symbolSize'
left: 0, // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px)
right: null, // The same as left.
top: null, // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px)
bottom: 0, // The same as top.
itemWidth: null,
itemHeight: null,
inverse: false,
orient: 'vertical', // 'horizontal' ¦ 'vertical'
backgroundColor: 'rgba(0,0,0,0)',
borderColor: '#ccc', // 值域边框颜色
contentColor: '#5793f3',
inactiveColor: '#aaa',
borderWidth: 0, // 值域边框线宽,单位px,默认为0(无边框)
padding: 5, // 值域内边距,单位px,默认各方向内边距为5,
// 接受数组分别设定上右下左边距,同css
textGap: 10, //
precision: 0, // 小数精度,默认为0,无小数点
color: ['#bf444c', '#d88273', '#f6efa6'], //颜色(deprecated,兼容ec2,顺序同pieces,不同于inRange/outOfRange)
formatter: null,
text: null, // 文本,如['高', '低'],兼容ec2,text[0]对应高值,text[1]对应低值
textStyle: {
color: '#333' // 值域文字颜色
}
},
/**
* @protected
*/
init: function (option, parentModel, ecModel) {
/**
* @private
* @type {Array.<number>}
*/
this._dataExtent;
/**
* @readOnly
*/
this.targetVisuals = {};
/**
* @readOnly
*/
this.controllerVisuals = {};
/**
* @readOnly
*/
this.textStyleModel;
/**
* [width, height]
* @readOnly
* @type {Array.<number>}
*/
this.itemSize;
ControllerModel.superApply(this, 'init', arguments);
},
/**
* @protected
*/
optionUpdated: function (newOption, isInit) {
ControllerModel.superApply(this, 'optionUpdated', arguments);
this.textStyleModel = this.getModel('textStyle');
this.resetItemSize();
this.completeVisualOption();
},
/**
* @example
* this.formatValueText(someVal); // format single numeric value to text.
* this.formatValueText(someVal, true); // format single category value to text.
* this.formatValueText([min, max]); // format numeric min-max to text.
* this.formatValueText([this.dataBound[0], max]); // using data lower bound.
* this.formatValueText([min, this.dataBound[1]]); // using data upper bound.
*
* @param {number|Array.<number>} value Real value, or this.dataBound[0 or 1].
* @param {boolean} [isCategory=false] Only available when value is number.
* @return {string}
* @protected
*/
formatValueText: function(value, isCategory) {
var option = this.option;
var precision = option.precision;
var dataBound = this.dataBound;
var formatter = option.formatter;
var isMinMax;
var textValue;
if (zrUtil.isArray(value)) {
value = value.slice();
isMinMax = true;
}
textValue = isCategory
? value
: (isMinMax
? [toFixed(value[0]), toFixed(value[1])]
: toFixed(value)
);
if (zrUtil.isString(formatter)) {
return formatter
.replace('{value}', isMinMax ? textValue[0] : textValue)
.replace('{value2}', isMinMax ? textValue[1] : textValue);
}
else if (zrUtil.isFunction(formatter)) {
return isMinMax
? formatter(value[0], value[1])
: formatter(value);
}
if (isMinMax) {
if (value[0] === dataBound[0]) {
return '< ' + textValue[1];
}
else if (value[1] === dataBound[1]) {
return '> ' + textValue[0];
}
else {
return textValue[0] + ' - ' + textValue[1];
}
}
else { // Format single value (includes category case).
return textValue;
}
function toFixed(val) {
return val === dataBound[0]
? 'min'
: val === dataBound[1]
? 'max'
: (+val).toFixed(precision);
}
},
/**
* @protected
*/
resetExtent: function () {
var thisOption = this.option;
// Can not calculate data extent by data here.
// Because series and data may be modified in processing stage.
// So we do not support the feature "auto min/max".
var extent = asc([thisOption.min, thisOption.max]);
this._dataExtent = extent;
},
/**
* @protected
*/
getDataDimension: function (list) {
var optDim = this.option.dimension;
return optDim != null
? optDim : list.dimensions.length - 1;
},
/**
* @public
* @override
*/
getExtent: function () {
return this._dataExtent.slice();
},
/**
* @protected
*/
completeVisualOption: function () {
var thisOption = this.option;
var base = {inRange: thisOption.inRange, outOfRange: thisOption.outOfRange};
var target = thisOption.target || (thisOption.target = {});
var controller = thisOption.controller || (thisOption.controller = {});
zrUtil.merge(target, base); // Do not override
zrUtil.merge(controller, base); // Do not override
var isCategory = this.isCategory();
completeSingle.call(this, target);
completeSingle.call(this, controller);
completeInactive.call(this, target, 'inRange', 'outOfRange');
completeInactive.call(this, target, 'outOfRange', 'inRange');
completeController.call(this, controller);
function completeSingle(base) {
// Compatible with ec2 dataRange.color.
// The mapping order of dataRange.color is: [high value, ..., low value]
// whereas inRange.color and outOfRange.color is [low value, ..., high value]
// Notice: ec2 has no inverse.
if (isArray(thisOption.color)
// If there has been inRange: {symbol: ...}, adding color is a mistake.
// So adding color only when no inRange defined.
&& !base.inRange
) {
base.inRange = {color: thisOption.color.slice().reverse()};
}
// If using shortcut like: {inRange: 'symbol'}, complete default value.
each(this.stateList, function (state) {
var visualType = base[state];
if (zrUtil.isString(visualType)) {
var defa = visualDefault.get(visualType, 'active', isCategory);
if (defa) {
base[state] = {};
base[state][visualType] = defa;
}
else {
// Mark as not specified.
delete base[state];
}
}
}, this);
}
function completeInactive(base, stateExist, stateAbsent) {
var optExist = base[stateExist];
var optAbsent = base[stateAbsent];
if (optExist && !optAbsent) {
optAbsent = base[stateAbsent] = {};
each(optExist, function (visualData, visualType) {
if (!VisualMapping.isValidType(visualType)) {
return;
}
var defa = visualDefault.get(visualType, 'inactive', isCategory);
if (defa != null) {
optAbsent[visualType] = defa;
// Compatibable with ec2:
// Only inactive color to rgba(0,0,0,0) can not
// make label transparent, so use opacity also.
if (visualType === 'color'
&& !optAbsent.hasOwnProperty('opacity')
&& !optAbsent.hasOwnProperty('colorAlpha')
) {
optAbsent.opacity = [0, 0];
}
}
});
}
}
function completeController(controller) {
var symbolExists = (controller.inRange || {}).symbol
|| (controller.outOfRange || {}).symbol;
var symbolSizeExists = (controller.inRange || {}).symbolSize
|| (controller.outOfRange || {}).symbolSize;
var inactiveColor = this.get('inactiveColor');
each(this.stateList, function (state) {
var itemSize = this.itemSize;
var visuals = controller[state];
// Set inactive color for controller if no other color
// attr (like colorAlpha) specified.
if (!visuals) {
visuals = controller[state] = {
color: isCategory ? inactiveColor : [inactiveColor]
};
}
// Consistent symbol and symbolSize if not specified.
if (visuals.symbol == null) {
visuals.symbol = symbolExists
&& zrUtil.clone(symbolExists)
|| (isCategory ? 'roundRect' : ['roundRect']);
}
if (visuals.symbolSize == null) {
visuals.symbolSize = symbolSizeExists
&& zrUtil.clone(symbolSizeExists)
|| (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]);
}
// Filter square and none.
visuals.symbol = mapVisual(visuals.symbol, function (symbol) {
return (symbol === 'none' || symbol === 'square') ? 'roundRect' : symbol;
});
// Normalize symbolSize
var symbolSize = visuals.symbolSize;
if (symbolSize != null) {
var max = -Infinity;
// symbolSize can be object when categories defined.
eachVisual(symbolSize, function (value) {
value > max && (max = value);
});
visuals.symbolSize = mapVisual(symbolSize, function (value) {
return linearMap(value, [0, max], [0, itemSize[0]], true);
});
}
}, this);
}
},
/**
* @protected
*/
resetItemSize: function () {
this.itemSize = [
parseFloat(this.get('itemWidth')),
parseFloat(this.get('itemHeight'))
];
},
/**
* @public
*/
isCategory: function () {
return !!this.option.categories;
}
});
return ControllerModel;
});
\ No newline at end of file
define(function (require) {
var VisualMapView = require('./VisualMapView');
var zrUtil = require('zrender/core/util');
var graphic = require('../../util/graphic');
var formatUtil = require('../../util/format');
var layout = require('../../util/layout');
var VisualMapping = require('../../visual/VisualMapping');
return VisualMapView.extend({
/**
* @readOnly
* @type {Object}
*/
autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1},
/**
* @protected
*/
render: function (visualMapModel, ecModel, api, payload) {
this.visualMapModel = visualMapModel;
if (visualMapModel.get('show') === false) {
this.group.removeAll();
return;
}
this.doRender.apply(this, arguments);
},
/**
* @protected
*/
renderBackground: function (group) {
var visualMapModel = this.visualMapModel;
var padding = formatUtil.normalizeCssArray(visualMapModel.get('padding') || 0);
var rect = group.getBoundingRect();
group.add(new graphic.Rect({
z2: -1, // Lay background rect on the lowest layer.
silent: true,
shape: {
x: rect.x - padding[3],
y: rect.y - padding[0],
width: rect.width + padding[3] + padding[1],
height: rect.height + padding[0] + padding[2]
},
style: {
fill: visualMapModel.get('backgroundColor'),
stroke: visualMapModel.get('borderColor'),
lineWidth: visualMapModel.get('borderWidth')
}
}));
},
/**
* @protected
* @param {number} targetValue
* @param {string=} visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize'
* @param {Object} [opts]
* @param {string=} [opts.forceState] Specify state, instead of using getValueState method.
* @param {string=} [opts.convertOpacityToAlpha=false] For color gradient in controller widget.
* @return {*} Visual value.
*/
getControllerVisual: function (targetValue, visualCluster, opts) {
opts = opts || {};
var forceState = opts.forceState;
var visualMapModel = this.visualMapModel;
var visualObj = {};
// Default values.
if (visualCluster === 'symbol') {
visualObj.symbol = visualMapModel.get('itemSymbol');
}
if (visualCluster === 'color') {
var defaultColor = visualMapModel.get('contentColor');
visualObj.color = defaultColor;
}
function getter(key) {
return visualObj[key];
}
function setter(key, value) {
visualObj[key] = value;
}
var mappings = visualMapModel.controllerVisuals[
forceState || visualMapModel.getValueState(targetValue)
];
var visualTypes = VisualMapping.prepareVisualTypes(mappings);
zrUtil.each(visualTypes, function (type) {
var visualMapping = mappings[type];
if (opts.convertOpacityToAlpha && type === 'opacity') {
type = 'colorAlpha';
visualMapping = mappings.__alphaForOpacity;
}
if (VisualMapping.dependsOn(type, visualCluster)) {
visualMapping && visualMapping.applyVisual(
targetValue, getter, setter
);
}
});
return visualObj[visualCluster];
},
/**
* @protected
*/
positionGroup: function (group) {
var model = this.visualMapModel;
var api = this.api;
layout.positionGroup(
group,
model.getBoxLayoutParams(),
{width: api.getWidth(), height: api.getHeight()}
);
},
/**
* @protected
* @abstract
*/
doRender: zrUtil.noop
});
});
\ No newline at end of file
define(function(require) {
var VisualMapModel = require('./VisualMapModel');
var ControllerModel = require('./ControllerModel');
var zrUtil = require('zrender/core/util');
var VisualMapping = require('../../visual/VisualMapping');
var PiecewiseModel = VisualMapModel.extend({
var PiecewiseModel = ControllerModel.extend({
type: 'visualMap.piecewise',
......@@ -60,8 +60,8 @@ define(function(require) {
/**
* @override
*/
doMergeOption: function (newOption, isInit) {
PiecewiseModel.superApply(this, 'doMergeOption', arguments);
optionUpdated: function (newOption, isInit) {
PiecewiseModel.superApply(this, 'optionUpdated', arguments);
/**
* The order is always [low, ..., high].
......@@ -71,7 +71,7 @@ define(function(require) {
*/
this._pieceList = [];
this.resetTargetSeries(newOption, isInit);
this.resetTargetSeries();
this.resetExtent();
/**
......@@ -85,12 +85,17 @@ define(function(require) {
this._resetSelected(newOption, isInit);
var categories = this.option.categories;
this.resetVisual(function (mappingOption, state) {
this.resetVisual('controller', this.controllerVisuals, fillVisualOption);
this.resetVisual('target', this.targetVisuals, fillVisualOption);
function fillVisualOption(mappingOption, state) {
if (mode === 'categories') {
mappingOption.mappingMethod = 'category';
mappingOption.categories = zrUtil.clone(categories);
}
else {
mappingOption.dataExtent = this.getExtent();
mappingOption.mappingMethod = 'piecewise';
mappingOption.pieceList = zrUtil.map(this._pieceList, function (piece) {
var piece = zrUtil.clone(piece);
......@@ -100,7 +105,7 @@ define(function(require) {
return piece;
});
}
});
}
},
_resetSelected: function (newOption, isInit) {
......@@ -204,7 +209,7 @@ define(function(require) {
pIdx === pieceIndex && dataIndices.push(dataIndex);
}, true, this);
result.push({seriesId: seriesModel.id, dataIndices: dataIndices});
result.push({seriesId: seriesModel.id, dataIndex: dataIndices});
}, this);
return result;
......
define(function(require) {
var VisualMapView = require('./VisualMapView');
var ControllerView = require('./ControllerView');
var zrUtil = require('zrender/core/util');
var graphic = require('../../util/graphic');
var symbolCreators = require('../../util/symbol');
var layout = require('../../util/layout');
var helper = require('./helper');
var PiecewiseVisualMapView = VisualMapView.extend({
var PiecewiseVisualMapView = ControllerView.extend({
type: 'visualMap.piecewise',
......@@ -94,9 +94,7 @@ define(function(require) {
visualMapModel.option.hoverLink && this.api.dispatchAction({
type: method,
batch: helper.convertDataIndicesToBatch(
visualMapModel.findTargetDataIndices(pieceIndex)
)
batch: visualMapModel.findTargetDataIndices(pieceIndex)
});
}
},
......
define(function (require) {
var echarts = require('../../echarts');
var zrUtil = require('zrender/core/util');
var graphic = require('../../util/graphic');
var formatUtil = require('../../util/format');
var layout = require('../../util/layout');
var VisualMapping = require('../../visual/VisualMapping');
return echarts.extendComponentView({
type: 'visualMap',
/**
* @readOnly
* @type {Object}
*/
autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1},
init: function (ecModel, api) {
/**
* @readOnly
......@@ -35,126 +24,7 @@ define(function (require) {
* @type {module:echarts/component/visualMap/visualMapModel}
*/
this.visualMapModel;
/**
* @private
* @type {Object}
*/
this._updatableShapes = {};
},
/**
* @protected
*/
render: function (visualMapModel, ecModel, api, payload) {
this.visualMapModel = visualMapModel;
if (visualMapModel.get('show') === false) {
this.group.removeAll();
return;
}
this.doRender.apply(this, arguments);
},
/**
* @protected
*/
renderBackground: function (group) {
var visualMapModel = this.visualMapModel;
var padding = formatUtil.normalizeCssArray(visualMapModel.get('padding') || 0);
var rect = group.getBoundingRect();
group.add(new graphic.Rect({
z2: -1, // Lay background rect on the lowest layer.
silent: true,
shape: {
x: rect.x - padding[3],
y: rect.y - padding[0],
width: rect.width + padding[3] + padding[1],
height: rect.height + padding[0] + padding[2]
},
style: {
fill: visualMapModel.get('backgroundColor'),
stroke: visualMapModel.get('borderColor'),
lineWidth: visualMapModel.get('borderWidth')
}
}));
},
/**
* @protected
* @param {number} targetValue
* @param {string=} visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize'
* @param {Object} [opts]
* @param {string=} [opts.forceState] Specify state, instead of using getValueState method.
* @param {string=} [opts.convertOpacityToAlpha=false] For color gradient in controller widget.
* @return {*} Visual value.
*/
getControllerVisual: function (targetValue, visualCluster, opts) {
opts = opts || {};
var forceState = opts.forceState;
var visualMapModel = this.visualMapModel;
var visualObj = {};
// Default values.
if (visualCluster === 'symbol') {
visualObj.symbol = visualMapModel.get('itemSymbol');
}
if (visualCluster === 'color') {
var defaultColor = visualMapModel.get('contentColor');
visualObj.color = defaultColor;
}
function getter(key) {
return visualObj[key];
}
function setter(key, value) {
visualObj[key] = value;
}
var mappings = visualMapModel.controllerVisuals[
forceState || visualMapModel.getValueState(targetValue)
];
var visualTypes = VisualMapping.prepareVisualTypes(mappings);
zrUtil.each(visualTypes, function (type) {
var visualMapping = mappings[type];
if (opts.convertOpacityToAlpha && type === 'opacity') {
type = 'colorAlpha';
visualMapping = mappings.__alphaForOpacity;
}
if (VisualMapping.dependsOn(type, visualCluster)) {
visualMapping && visualMapping.applyVisual(
targetValue, getter, setter
);
}
});
return visualObj[visualCluster];
},
/**
* @protected
*/
positionGroup: function (group) {
var model = this.visualMapModel;
var api = this.api;
layout.positionGroup(
group,
model.getBoxLayoutParams(),
{width: api.getWidth(), height: api.getHeight()}
);
},
/**
* @protected
* @abstract
*/
doRender: zrUtil.noop
}
});
......
define(function(require) {
var layout = require('../../util/layout');
var zrUtil = require('zrender/core/util');
var helper = {
......@@ -43,16 +42,6 @@ define(function(require) {
(rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5
< ecSize[rParam[1]] * 0.5 ? 0 : 1
];
},
convertDataIndicesToBatch: function (dataIndicesBySeries) {
var batch = [];
zrUtil.each(dataIndicesBySeries, function (item) {
zrUtil.each(item.dataIndices, function (dataIndex) {
batch.push({seriesId: item.seriesId, dataIndex: dataIndex});
});
});
return batch;
}
};
......
......@@ -115,7 +115,7 @@ define(function(require) {
},
// Hooker after init or mergeOption
optionUpdated: function (ecModel) {},
optionUpdated: function (newCptOption, isInit) {},
getDefaultOption: function () {
if (!this.hasOwnProperty('__defaultOption')) {
......
......@@ -166,7 +166,7 @@ define(function (require) {
// ComponentModel.getAllClassMainTypes.
if (!newCptOption) {
componentModel.mergeOption({}, this);
componentModel.optionUpdated(this);
componentModel.optionUpdated({}, false);
}
else {
var ComponentModelClass = ComponentModel.getClass(
......@@ -175,7 +175,7 @@ define(function (require) {
if (componentModel && componentModel instanceof ComponentModelClass) {
componentModel.mergeOption(newCptOption, this);
componentModel.optionUpdated(this);
componentModel.optionUpdated(newCptOption, false);
}
else {
// PENDING Global as parent ?
......@@ -190,7 +190,7 @@ define(function (require) {
)
);
// Call optionUpdated after init
componentModel.optionUpdated(this);
componentModel.optionUpdated(newCptOption, true);
}
}
......
......@@ -3,7 +3,6 @@ define(function(require) {
var formatUtil = require('./format');
var nubmerUtil = require('./number');
var zrUtil = require('zrender/core/util');
var DataDiffer = require('../data/DataDiffer');
var AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle'];
......@@ -65,7 +64,7 @@ define(function(require) {
* @return {Array} [value] or value
*/
modelUtil.normalizeToArray = function (value) {
return zrUtil.isArray(value)
return value instanceof Array
? value
: value == null
? []
......@@ -401,29 +400,56 @@ define(function(require) {
};
/**
* @param {Array} collectionA
* @param {Array} collectionB
* @param {Function} getKey
* @return {Array.<Array, Array>} result: [resultCollectionA, resultCollectionB]
* A helper for removing duplicate items between batchA and batchB,
* and in themselves, and categorize by series.
*
* @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
* @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
* @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]
*/
modelUtil.removeDuplicate = function (collectionA, collectionB, getKey) {
var result = [[], []];
(new DataDiffer(collectionA || [], collectionB || [], getKey, getKey))
.add(add)
.update(zrUtil.noop)
.remove(remove)
.execute();
function add(index) {
result[1].push(collectionB[index]);
modelUtil.compressBatches = function (batchA, batchB) {
var mapA = {};
var mapB = {};
makeMap(batchA || [], mapA);
makeMap(batchB || [], mapB, mapA);
return [mapToArray(mapA), mapToArray(mapB)];
function makeMap(sourceBatch, map, otherMap) {
for (var i = 0, len = sourceBatch.length; i < len; i++) {
var seriesId = sourceBatch[i].seriesId;
var dataIndices = modelUtil.normalizeToArray(sourceBatch[i].dataIndex);
var otherDataIndices = otherMap && otherMap[seriesId];
for (var j = 0, lenj = dataIndices.length; j < lenj; j++) {
var dataIndex = dataIndices[j];
if (otherDataIndices && otherDataIndices[dataIndex]) {
otherDataIndices[dataIndex] = null;
}
else {
(map[seriesId] || (map[seriesId] = {}))[dataIndex] = 1;
}
}
}
}
function remove(index) {
result[0].push(collectionA[index]);
function mapToArray(map, isData) {
var result = [];
for (var i in map) {
if (map.hasOwnProperty(i) && map[i] != null) {
if (isData) {
result.push(+i);
}
else {
var dataIndices = mapToArray(map[i], true);
dataIndices.length && result.push({seriesId: i, dataIndex: dataIndices});
}
};
}
return result;
}
return result;
};
return modelUtil;
......
......@@ -97,4 +97,77 @@ describe('util/model', function() {
});
describe('compressBatches', function () {
function item(seriesId, dataIndex) {
return {seriesId: seriesId, dataIndex: dataIndex};
}
it('base', function (done) {
// Remove dupliate between A and B
expect(modelUtil.compressBatches(
[item(3, 4), item(3, 5), item(4, 5)],
[item(4, 6), item(4, 5), item(3, 3), item(3, 4)]
)).toEqual([
[item('3', [5])],
[item('3', [3]), item('4', [6])]
]);
// Compress
expect(modelUtil.compressBatches(
[item(3, 4), item(3, 6), item(3, 5), item(4, 5)],
[item(4, 6), item(4, 5), item(3, 3), item(3, 4), item(4, 7)]
)).toEqual([
[item('3', [5, 6])],
[item('3', [3]), item('4', [6, 7])]
]);
// Remove duplicate in themselves
expect(modelUtil.compressBatches(
[item(3, 4), item(3, 6), item(3, 5), item(4, 5)],
[item(4, 6), item(4, 5), item(3, 3), item(3, 4), item(4, 7), item(4, 6)]
)).toEqual([
[item('3', [5, 6])],
[item('3', [3]), item('4', [6, 7])]
]);
// dataIndex is array
expect(modelUtil.compressBatches(
[item(3, [4, 5, 8]), item(4, 4), item(3, [5, 7, 7])],
[item(3, [8, 9])]
)).toEqual([
[item('3', [4, 5, 7]), item('4', [4])],
[item('3', [9])]
]);
// empty
expect(modelUtil.compressBatches(
[item(3, [4, 5, 8]), item(4, 4), item(3, [5, 7, 7])],
[]
)).toEqual([
[item('3', [4, 5, 7, 8]), item('4', [4])],
[]
]);
expect(modelUtil.compressBatches(
[],
[item(3, [4, 5, 8]), item(4, 4), item(3, [5, 7, 7])]
)).toEqual([
[],
[item('3', [4, 5, 7, 8]), item('4', [4])]
]);
// should not has empty array
expect(modelUtil.compressBatches(
[item(3, [4, 5, 8])],
[item(3, [4, 5, 8])]
)).toEqual([
[],
[]
]);
done();
});
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册