|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
|
|
|
* or more contributor license agreements. See the NOTICE file
|
|
|
|
|
* distributed with this work for additional information
|
|
|
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
|
|
|
* to you under the Apache License, Version 2.0 (the
|
|
|
|
|
* "License"); you may not use this file except in compliance
|
|
|
|
|
* with the License. You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing,
|
|
|
|
|
* software distributed under the License is distributed on an
|
|
|
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
|
* KIND, either express or implied. See the License for the
|
|
|
|
|
* specific language governing permissions and limitations
|
|
|
|
|
* under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* AUTO-GENERATED FILE. DO NOT MODIFY.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
|
|
|
* or more contributor license agreements. See the NOTICE file
|
|
|
|
|
* distributed with this work for additional information
|
|
|
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
|
|
|
* to you under the Apache License, Version 2.0 (the
|
|
|
|
|
* "License"); you may not use this file except in compliance
|
|
|
|
|
* with the License. You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing,
|
|
|
|
|
* software distributed under the License is distributed on an
|
|
|
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
|
* KIND, either express or implied. See the License for the
|
|
|
|
|
* specific language governing permissions and limitations
|
|
|
|
|
* under the License.
|
|
|
|
|
*/
|
|
|
|
|
import { __extends } from "tslib";
|
|
|
|
|
import * as zrUtil from 'zrender/lib/core/util.js';
|
|
|
|
|
import VisualMapModel from './VisualMapModel.js';
|
|
|
|
|
import VisualMapping from '../../visual/VisualMapping.js';
|
|
|
|
|
import visualDefault from '../../visual/visualDefault.js';
|
|
|
|
|
import { reformIntervals } from '../../util/number.js';
|
|
|
|
|
import { inheritDefaultOption } from '../../util/component.js';
|
|
|
|
|
var PiecewiseModel = /** @class */function (_super) {
|
|
|
|
|
__extends(PiecewiseModel, _super);
|
|
|
|
|
function PiecewiseModel() {
|
|
|
|
|
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
|
|
|
_this.type = PiecewiseModel.type;
|
|
|
|
|
/**
|
|
|
|
|
* The order is always [low, ..., high].
|
|
|
|
|
* [{text: string, interval: Array.<number>}, ...]
|
|
|
|
|
*/
|
|
|
|
|
_this._pieceList = [];
|
|
|
|
|
return _this;
|
|
|
|
|
}
|
|
|
|
|
PiecewiseModel.prototype.optionUpdated = function (newOption, isInit) {
|
|
|
|
|
_super.prototype.optionUpdated.apply(this, arguments);
|
|
|
|
|
this.resetExtent();
|
|
|
|
|
var mode = this._mode = this._determineMode();
|
|
|
|
|
this._pieceList = [];
|
|
|
|
|
resetMethods[this._mode].call(this, this._pieceList);
|
|
|
|
|
this._resetSelected(newOption, isInit);
|
|
|
|
|
var categories = this.option.categories;
|
|
|
|
|
this.resetVisual(function (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) {
|
|
|
|
|
piece = zrUtil.clone(piece);
|
|
|
|
|
if (state !== 'inRange') {
|
|
|
|
|
// FIXME
|
|
|
|
|
// outOfRange do not support special visual in pieces.
|
|
|
|
|
piece.visual = null;
|
|
|
|
|
}
|
|
|
|
|
return piece;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @protected
|
|
|
|
|
* @override
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.completeVisualOption = function () {
|
|
|
|
|
// Consider this case:
|
|
|
|
|
// visualMap: {
|
|
|
|
|
// pieces: [{symbol: 'circle', lt: 0}, {symbol: 'rect', gte: 0}]
|
|
|
|
|
// }
|
|
|
|
|
// where no inRange/outOfRange set but only pieces. So we should make
|
|
|
|
|
// default inRange/outOfRange for this case, otherwise visuals that only
|
|
|
|
|
// appear in `pieces` will not be taken into account in visual encoding.
|
|
|
|
|
var option = this.option;
|
|
|
|
|
var visualTypesInPieces = {};
|
|
|
|
|
var visualTypes = VisualMapping.listVisualTypes();
|
|
|
|
|
var isCategory = this.isCategory();
|
|
|
|
|
zrUtil.each(option.pieces, function (piece) {
|
|
|
|
|
zrUtil.each(visualTypes, function (visualType) {
|
|
|
|
|
if (piece.hasOwnProperty(visualType)) {
|
|
|
|
|
visualTypesInPieces[visualType] = 1;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
zrUtil.each(visualTypesInPieces, function (v, visualType) {
|
|
|
|
|
var exists = false;
|
|
|
|
|
zrUtil.each(this.stateList, function (state) {
|
|
|
|
|
exists = exists || has(option, state, visualType) || has(option.target, state, visualType);
|
|
|
|
|
}, this);
|
|
|
|
|
!exists && zrUtil.each(this.stateList, function (state) {
|
|
|
|
|
(option[state] || (option[state] = {}))[visualType] = visualDefault.get(visualType, state === 'inRange' ? 'active' : 'inactive', isCategory);
|
|
|
|
|
});
|
|
|
|
|
}, this);
|
|
|
|
|
function has(obj, state, visualType) {
|
|
|
|
|
return obj && obj[state] && obj[state].hasOwnProperty(visualType);
|
|
|
|
|
}
|
|
|
|
|
_super.prototype.completeVisualOption.apply(this, arguments);
|
|
|
|
|
};
|
|
|
|
|
PiecewiseModel.prototype._resetSelected = function (newOption, isInit) {
|
|
|
|
|
var thisOption = this.option;
|
|
|
|
|
var pieceList = this._pieceList;
|
|
|
|
|
// Selected do not merge but all override.
|
|
|
|
|
var selected = (isInit ? thisOption : newOption).selected || {};
|
|
|
|
|
thisOption.selected = selected;
|
|
|
|
|
// Consider 'not specified' means true.
|
|
|
|
|
zrUtil.each(pieceList, function (piece, index) {
|
|
|
|
|
var key = this.getSelectedMapKey(piece);
|
|
|
|
|
if (!selected.hasOwnProperty(key)) {
|
|
|
|
|
selected[key] = true;
|
|
|
|
|
}
|
|
|
|
|
}, this);
|
|
|
|
|
if (thisOption.selectedMode === 'single') {
|
|
|
|
|
// Ensure there is only one selected.
|
|
|
|
|
var hasSel_1 = false;
|
|
|
|
|
zrUtil.each(pieceList, function (piece, index) {
|
|
|
|
|
var key = this.getSelectedMapKey(piece);
|
|
|
|
|
if (selected[key]) {
|
|
|
|
|
hasSel_1 ? selected[key] = false : hasSel_1 = true;
|
|
|
|
|
}
|
|
|
|
|
}, this);
|
|
|
|
|
}
|
|
|
|
|
// thisOption.selectedMode === 'multiple', default: all selected.
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.getItemSymbol = function () {
|
|
|
|
|
return this.get('itemSymbol');
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.getSelectedMapKey = function (piece) {
|
|
|
|
|
return this._mode === 'categories' ? piece.value + '' : piece.index + '';
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @public
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.getPieceList = function () {
|
|
|
|
|
return this._pieceList;
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @return {string}
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype._determineMode = function () {
|
|
|
|
|
var option = this.option;
|
|
|
|
|
return option.pieces && option.pieces.length > 0 ? 'pieces' : this.option.categories ? 'categories' : 'splitNumber';
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @override
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.setSelected = function (selected) {
|
|
|
|
|
this.option.selected = zrUtil.clone(selected);
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @override
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.getValueState = function (value) {
|
|
|
|
|
var index = VisualMapping.findPieceIndex(value, this._pieceList);
|
|
|
|
|
return index != null ? this.option.selected[this.getSelectedMapKey(this._pieceList[index])] ? 'inRange' : 'outOfRange' : 'outOfRange';
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @public
|
|
|
|
|
* @param pieceIndex piece index in visualMapModel.getPieceList()
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.findTargetDataIndices = function (pieceIndex) {
|
|
|
|
|
var result = [];
|
|
|
|
|
var pieceList = this._pieceList;
|
|
|
|
|
this.eachTargetSeries(function (seriesModel) {
|
|
|
|
|
var dataIndices = [];
|
|
|
|
|
var data = seriesModel.getData();
|
|
|
|
|
data.each(this.getDataDimensionIndex(data), function (value, dataIndex) {
|
|
|
|
|
// Should always base on model pieceList, because it is order sensitive.
|
|
|
|
|
var pIdx = VisualMapping.findPieceIndex(value, pieceList);
|
|
|
|
|
pIdx === pieceIndex && dataIndices.push(dataIndex);
|
|
|
|
|
}, this);
|
|
|
|
|
result.push({
|
|
|
|
|
seriesId: seriesModel.id,
|
|
|
|
|
dataIndex: dataIndices
|
|
|
|
|
});
|
|
|
|
|
}, this);
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @param piece piece.value or piece.interval is required.
|
|
|
|
|
* @return Can be Infinity or -Infinity
|
|
|
|
|
*/
|
|
|
|
|
PiecewiseModel.prototype.getRepresentValue = function (piece) {
|
|
|
|
|
var representValue;
|
|
|
|
|
if (this.isCategory()) {
|
|
|
|
|
representValue = piece.value;
|
|
|
|
|
} else {
|
|
|
|
|
if (piece.value != null) {
|
|
|
|
|
representValue = piece.value;
|
|
|
|
|
} else {
|
|
|
|
|
var pieceInterval = piece.interval || [];
|
|
|
|
|
representValue = pieceInterval[0] === -Infinity && pieceInterval[1] === Infinity ? 0 : (pieceInterval[0] + pieceInterval[1]) / 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return representValue;
|
|
|
|
|
};
|
|
|
|
|
PiecewiseModel.prototype.getVisualMeta = function (getColorVisual) {
|
|
|
|
|
// Do not support category. (category axis is ordinal, numerical)
|
|
|
|
|
if (this.isCategory()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var stops = [];
|
|
|
|
|
var outerColors = ['', ''];
|
|
|
|
|
var visualMapModel = this;
|
|
|
|
|
function setStop(interval, valueState) {
|
|
|
|
|
var representValue = visualMapModel.getRepresentValue({
|
|
|
|
|
interval: interval
|
|
|
|
|
}); // Not category
|
|
|
|
|
if (!valueState) {
|
|
|
|
|
valueState = visualMapModel.getValueState(representValue);
|
|
|
|
|
}
|
|
|
|
|
var color = getColorVisual(representValue, valueState);
|
|
|
|
|
if (interval[0] === -Infinity) {
|
|
|
|
|
outerColors[0] = color;
|
|
|
|
|
} else if (interval[1] === Infinity) {
|
|
|
|
|
outerColors[1] = color;
|
|
|
|
|
} else {
|
|
|
|
|
stops.push({
|
|
|
|
|
value: interval[0],
|
|
|
|
|
color: color
|
|
|
|
|
}, {
|
|
|
|
|
value: interval[1],
|
|
|
|
|
color: color
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Suplement
|
|
|
|
|
var pieceList = this._pieceList.slice();
|
|
|
|
|
if (!pieceList.length) {
|
|
|
|
|
pieceList.push({
|
|
|
|
|
interval: [-Infinity, Infinity]
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
var edge = pieceList[0].interval[0];
|
|
|
|
|
edge !== -Infinity && pieceList.unshift({
|
|
|
|
|
interval: [-Infinity, edge]
|
|
|
|
|
});
|
|
|
|
|
edge = pieceList[pieceList.length - 1].interval[1];
|
|
|
|
|
edge !== Infinity && pieceList.push({
|
|
|
|
|
interval: [edge, Infinity]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
var curr = -Infinity;
|
|
|
|
|
zrUtil.each(pieceList, function (piece) {
|
|
|
|
|
var interval = piece.interval;
|
|
|
|
|
if (interval) {
|
|
|
|
|
// Fulfill gap.
|
|
|
|
|
interval[0] > curr && setStop([curr, interval[0]], 'outOfRange');
|
|
|
|
|
setStop(interval.slice());
|
|
|
|
|
curr = interval[1];
|
|
|
|
|
}
|
|
|
|
|
}, this);
|
|
|
|
|
return {
|
|
|
|
|
stops: stops,
|
|
|
|
|
outerColors: outerColors
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
PiecewiseModel.type = 'visualMap.piecewise';
|
|
|
|
|
PiecewiseModel.defaultOption = inheritDefaultOption(VisualMapModel.defaultOption, {
|
|
|
|
|
selected: null,
|
|
|
|
|
minOpen: false,
|
|
|
|
|
maxOpen: false,
|
|
|
|
|
align: 'auto',
|
|
|
|
|
itemWidth: 20,
|
|
|
|
|
itemHeight: 14,
|
|
|
|
|
itemSymbol: 'roundRect',
|
|
|
|
|
pieces: null,
|
|
|
|
|
categories: null,
|
|
|
|
|
splitNumber: 5,
|
|
|
|
|
selectedMode: 'multiple',
|
|
|
|
|
itemGap: 10,
|
|
|
|
|
hoverLink: true // Enable hover highlight.
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return PiecewiseModel;
|
|
|
|
|
}(VisualMapModel);
|
|
|
|
|
;
|
|
|
|
|
/**
|
|
|
|
|
* Key is this._mode
|
|
|
|
|
* @type {Object}
|
|
|
|
|
* @this {module:echarts/component/viusalMap/PiecewiseMode}
|
|
|
|
|
*/
|
|
|
|
|
var resetMethods = {
|
|
|
|
|
splitNumber: function (outPieceList) {
|
|
|
|
|
var thisOption = this.option;
|
|
|
|
|
var precision = Math.min(thisOption.precision, 20);
|
|
|
|
|
var dataExtent = this.getExtent();
|
|
|
|
|
var splitNumber = thisOption.splitNumber;
|
|
|
|
|
splitNumber = Math.max(parseInt(splitNumber, 10), 1);
|
|
|
|
|
thisOption.splitNumber = splitNumber;
|
|
|
|
|
var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber;
|
|
|
|
|
// Precision auto-adaption
|
|
|
|
|
while (+splitStep.toFixed(precision) !== splitStep && precision < 5) {
|
|
|
|
|
precision++;
|
|
|
|
|
}
|
|
|
|
|
thisOption.precision = precision;
|
|
|
|
|
splitStep = +splitStep.toFixed(precision);
|
|
|
|
|
if (thisOption.minOpen) {
|
|
|
|
|
outPieceList.push({
|
|
|
|
|
interval: [-Infinity, dataExtent[0]],
|
|
|
|
|
close: [0, 0]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
for (var index = 0, curr = dataExtent[0]; index < splitNumber; curr += splitStep, index++) {
|
|
|
|
|
var max = index === splitNumber - 1 ? dataExtent[1] : curr + splitStep;
|
|
|
|
|
outPieceList.push({
|
|
|
|
|
interval: [curr, max],
|
|
|
|
|
close: [1, 1]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (thisOption.maxOpen) {
|
|
|
|
|
outPieceList.push({
|
|
|
|
|
interval: [dataExtent[1], Infinity],
|
|
|
|
|
close: [0, 0]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
reformIntervals(outPieceList);
|
|
|
|
|
zrUtil.each(outPieceList, function (piece, index) {
|
|
|
|
|
piece.index = index;
|
|
|
|
|
piece.text = this.formatValueText(piece.interval);
|
|
|
|
|
}, this);
|
|
|
|
|
},
|
|
|
|
|
categories: function (outPieceList) {
|
|
|
|
|
var thisOption = this.option;
|
|
|
|
|
zrUtil.each(thisOption.categories, function (cate) {
|
|
|
|
|
// FIXME category模式也使用pieceList,但在visualMapping中不是使用pieceList。
|
|
|
|
|
// 是否改一致。
|
|
|
|
|
outPieceList.push({
|
|
|
|
|
text: this.formatValueText(cate, true),
|
|
|
|
|
value: cate
|
|
|
|
|
});
|
|
|
|
|
}, this);
|
|
|
|
|
// See "Order Rule".
|
|
|
|
|
normalizeReverse(thisOption, outPieceList);
|
|
|
|
|
},
|
|
|
|
|
pieces: function (outPieceList) {
|
|
|
|
|
var thisOption = this.option;
|
|
|
|
|
zrUtil.each(thisOption.pieces, function (pieceListItem, index) {
|
|
|
|
|
if (!zrUtil.isObject(pieceListItem)) {
|
|
|
|
|
pieceListItem = {
|
|
|
|
|
value: pieceListItem
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
var item = {
|
|
|
|
|
text: '',
|
|
|
|
|
index: index
|
|
|
|
|
};
|
|
|
|
|
if (pieceListItem.label != null) {
|
|
|
|
|
item.text = pieceListItem.label;
|
|
|
|
|
}
|
|
|
|
|
if (pieceListItem.hasOwnProperty('value')) {
|
|
|
|
|
var value = item.value = pieceListItem.value;
|
|
|
|
|
item.interval = [value, value];
|
|
|
|
|
item.close = [1, 1];
|
|
|
|
|
} else {
|
|
|
|
|
// `min` `max` is legacy option.
|
|
|
|
|
// `lt` `gt` `lte` `gte` is recommended.
|
|
|
|
|
var interval = item.interval = [];
|
|
|
|
|
var close_1 = item.close = [0, 0];
|
|
|
|
|
var closeList = [1, 0, 1];
|
|
|
|
|
var infinityList = [-Infinity, Infinity];
|
|
|
|
|
var useMinMax = [];
|
|
|
|
|
for (var lg = 0; lg < 2; lg++) {
|
|
|
|
|
var names = [['gte', 'gt', 'min'], ['lte', 'lt', 'max']][lg];
|
|
|
|
|
for (var i = 0; i < 3 && interval[lg] == null; i++) {
|
|
|
|
|
interval[lg] = pieceListItem[names[i]];
|
|
|
|
|
close_1[lg] = closeList[i];
|
|
|
|
|
useMinMax[lg] = i === 2;
|
|
|
|
|
}
|
|
|
|
|
interval[lg] == null && (interval[lg] = infinityList[lg]);
|
|
|
|
|
}
|
|
|
|
|
useMinMax[0] && interval[1] === Infinity && (close_1[0] = 0);
|
|
|
|
|
useMinMax[1] && interval[0] === -Infinity && (close_1[1] = 0);
|
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
|
if (interval[0] > interval[1]) {
|
|
|
|
|
console.warn('Piece ' + index + 'is illegal: ' + interval + ' lower bound should not greater then uppper bound.');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (interval[0] === interval[1] && close_1[0] && close_1[1]) {
|
|
|
|
|
// Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}],
|
|
|
|
|
// we use value to lift the priority when min === max
|
|
|
|
|
item.value = interval[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
item.visual = VisualMapping.retrieveVisuals(pieceListItem);
|
|
|
|
|
outPieceList.push(item);
|
|
|
|
|
}, this);
|
|
|
|
|
// See "Order Rule".
|
|
|
|
|
normalizeReverse(thisOption, outPieceList);
|
|
|
|
|
// Only pieces
|
|
|
|
|
reformIntervals(outPieceList);
|
|
|
|
|
zrUtil.each(outPieceList, function (piece) {
|
|
|
|
|
var close = piece.close;
|
|
|
|
|
var edgeSymbols = [['<', '≤'][close[1]], ['>', '≥'][close[0]]];
|
|
|
|
|
piece.text = piece.text || this.formatValueText(piece.value != null ? piece.value : piece.interval, false, edgeSymbols);
|
|
|
|
|
}, this);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
function normalizeReverse(thisOption, pieceList) {
|
|
|
|
|
var inverse = thisOption.inverse;
|
|
|
|
|
if (thisOption.orient === 'vertical' ? !inverse : inverse) {
|
|
|
|
|
pieceList.reverse();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
export default PiecewiseModel;
|