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.
652 lines
20 KiB
652 lines
20 KiB
|
|
/* |
|
* 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 env from 'zrender/lib/core/env.js'; |
|
import * as modelUtil from '../util/model.js'; |
|
import ComponentModel from './Component.js'; |
|
import { PaletteMixin } from './mixin/palette.js'; |
|
import { DataFormatMixin } from '../model/mixin/dataFormat.js'; |
|
import { getLayoutParams, mergeLayoutParam, fetchLayoutMode } from '../util/layout.js'; |
|
import { createTask } from '../core/task.js'; |
|
import { mountExtend } from '../util/clazz.js'; |
|
import { SourceManager } from '../data/helper/sourceManager.js'; |
|
import { defaultSeriesFormatTooltip } from '../component/tooltip/seriesFormatTooltip.js'; |
|
var inner = modelUtil.makeInner(); |
|
|
|
function getSelectionKey(data, dataIndex) { |
|
return data.getName(dataIndex) || data.getId(dataIndex); |
|
} |
|
|
|
export var SERIES_UNIVERSAL_TRANSITION_PROP = '__universalTransitionEnabled'; |
|
|
|
var SeriesModel = |
|
/** @class */ |
|
function (_super) { |
|
__extends(SeriesModel, _super); |
|
|
|
function SeriesModel() { |
|
// [Caution]: Because this class or desecendants can be used as `XXX.extend(subProto)`, |
|
// the class members must not be initialized in constructor or declaration place. |
|
// Otherwise there is bad case: |
|
// class A {xxx = 1;} |
|
// enableClassExtend(A); |
|
// class B extends A {} |
|
// var C = B.extend({xxx: 5}); |
|
// var c = new C(); |
|
// console.log(c.xxx); // expect 5 but always 1. |
|
var _this = _super !== null && _super.apply(this, arguments) || this; // --------------------------------------- |
|
// Props about data selection |
|
// --------------------------------------- |
|
|
|
|
|
_this._selectedDataIndicesMap = {}; |
|
return _this; |
|
} |
|
|
|
SeriesModel.prototype.init = function (option, parentModel, ecModel) { |
|
this.seriesIndex = this.componentIndex; |
|
this.dataTask = createTask({ |
|
count: dataTaskCount, |
|
reset: dataTaskReset |
|
}); |
|
this.dataTask.context = { |
|
model: this |
|
}; |
|
this.mergeDefaultAndTheme(option, ecModel); |
|
var sourceManager = inner(this).sourceManager = new SourceManager(this); |
|
sourceManager.prepareSource(); |
|
var data = this.getInitialData(option, ecModel); |
|
wrapData(data, this); |
|
this.dataTask.context.data = data; |
|
|
|
if (process.env.NODE_ENV !== 'production') { |
|
zrUtil.assert(data, 'getInitialData returned invalid data.'); |
|
} |
|
|
|
inner(this).dataBeforeProcessed = data; // If we reverse the order (make data firstly, and then make |
|
// dataBeforeProcessed by cloneShallow), cloneShallow will |
|
// cause data.graph.data !== data when using |
|
// module:echarts/data/Graph or module:echarts/data/Tree. |
|
// See module:echarts/data/helper/linkSeriesData |
|
// Theoretically, it is unreasonable to call `seriesModel.getData()` in the model |
|
// init or merge stage, because the data can be restored. So we do not `restoreData` |
|
// and `setData` here, which forbids calling `seriesModel.getData()` in this stage. |
|
// Call `seriesModel.getRawData()` instead. |
|
// this.restoreData(); |
|
|
|
autoSeriesName(this); |
|
|
|
this._initSelectedMapFromData(data); |
|
}; |
|
/** |
|
* Util for merge default and theme to option |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { |
|
var layoutMode = fetchLayoutMode(this); |
|
var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; // Backward compat: using subType on theme. |
|
// But if name duplicate between series subType |
|
// (for example: parallel) add component mainType, |
|
// add suffix 'Series'. |
|
|
|
var themeSubType = this.subType; |
|
|
|
if (ComponentModel.hasClass(themeSubType)) { |
|
themeSubType += 'Series'; |
|
} |
|
|
|
zrUtil.merge(option, ecModel.getTheme().get(this.subType)); |
|
zrUtil.merge(option, this.getDefaultOption()); // Default label emphasis `show` |
|
|
|
modelUtil.defaultEmphasis(option, 'label', ['show']); |
|
this.fillDataTextStyle(option.data); |
|
|
|
if (layoutMode) { |
|
mergeLayoutParam(option, inputPositionParams, layoutMode); |
|
} |
|
}; |
|
|
|
SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) { |
|
// this.settingTask.dirty(); |
|
newSeriesOption = zrUtil.merge(this.option, newSeriesOption, true); |
|
this.fillDataTextStyle(newSeriesOption.data); |
|
var layoutMode = fetchLayoutMode(this); |
|
|
|
if (layoutMode) { |
|
mergeLayoutParam(this.option, newSeriesOption, layoutMode); |
|
} |
|
|
|
var sourceManager = inner(this).sourceManager; |
|
sourceManager.dirty(); |
|
sourceManager.prepareSource(); |
|
var data = this.getInitialData(newSeriesOption, ecModel); |
|
wrapData(data, this); |
|
this.dataTask.dirty(); |
|
this.dataTask.context.data = data; |
|
inner(this).dataBeforeProcessed = data; |
|
autoSeriesName(this); |
|
|
|
this._initSelectedMapFromData(data); |
|
}; |
|
|
|
SeriesModel.prototype.fillDataTextStyle = function (data) { |
|
// Default data label emphasis `show` |
|
// FIXME Tree structure data ? |
|
// FIXME Performance ? |
|
if (data && !zrUtil.isTypedArray(data)) { |
|
var props = ['show']; |
|
|
|
for (var i = 0; i < data.length; i++) { |
|
if (data[i] && data[i].label) { |
|
modelUtil.defaultEmphasis(data[i], 'label', props); |
|
} |
|
} |
|
} |
|
}; |
|
/** |
|
* Init a data structure from data related option in series |
|
* Must be overridden. |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.getInitialData = function (option, ecModel) { |
|
return; |
|
}; |
|
/** |
|
* Append data to list |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.appendData = function (params) { |
|
// FIXME ??? |
|
// (1) If data from dataset, forbidden append. |
|
// (2) support append data of dataset. |
|
var data = this.getRawData(); |
|
data.appendData(params.data); |
|
}; |
|
/** |
|
* Consider some method like `filter`, `map` need make new data, |
|
* We should make sure that `seriesModel.getData()` get correct |
|
* data in the stream procedure. So we fetch data from upstream |
|
* each time `task.perform` called. |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.getData = function (dataType) { |
|
var task = getCurrentTask(this); |
|
|
|
if (task) { |
|
var data = task.context.data; |
|
return dataType == null ? data : data.getLinkedData(dataType); |
|
} else { |
|
// When series is not alive (that may happen when click toolbox |
|
// restore or setOption with not merge mode), series data may |
|
// be still need to judge animation or something when graphic |
|
// elements want to know whether fade out. |
|
return inner(this).data; |
|
} |
|
}; |
|
|
|
SeriesModel.prototype.getAllData = function () { |
|
var mainData = this.getData(); |
|
return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{ |
|
data: mainData |
|
}]; |
|
}; |
|
|
|
SeriesModel.prototype.setData = function (data) { |
|
var task = getCurrentTask(this); |
|
|
|
if (task) { |
|
var context = task.context; // Consider case: filter, data sample. |
|
// FIXME:TS never used, so comment it |
|
// if (context.data !== data && task.modifyOutputEnd) { |
|
// task.setOutputEnd(data.count()); |
|
// } |
|
|
|
context.outputData = data; // Caution: setData should update context.data, |
|
// Because getData may be called multiply in a |
|
// single stage and expect to get the data just |
|
// set. (For example, AxisProxy, x y both call |
|
// getData and setDate sequentially). |
|
// So the context.data should be fetched from |
|
// upstream each time when a stage starts to be |
|
// performed. |
|
|
|
if (task !== this.dataTask) { |
|
context.data = data; |
|
} |
|
} |
|
|
|
inner(this).data = data; |
|
}; |
|
|
|
SeriesModel.prototype.getEncode = function () { |
|
var encode = this.get('encode', true); |
|
|
|
if (encode) { |
|
return zrUtil.createHashMap(encode); |
|
} |
|
}; |
|
|
|
SeriesModel.prototype.getSourceManager = function () { |
|
return inner(this).sourceManager; |
|
}; |
|
|
|
SeriesModel.prototype.getSource = function () { |
|
return this.getSourceManager().getSource(); |
|
}; |
|
/** |
|
* Get data before processed |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.getRawData = function () { |
|
return inner(this).dataBeforeProcessed; |
|
}; |
|
|
|
SeriesModel.prototype.getColorBy = function () { |
|
var colorBy = this.get('colorBy'); |
|
return colorBy || 'series'; |
|
}; |
|
|
|
SeriesModel.prototype.isColorBySeries = function () { |
|
return this.getColorBy() === 'series'; |
|
}; |
|
/** |
|
* Get base axis if has coordinate system and has axis. |
|
* By default use coordSys.getBaseAxis(); |
|
* Can be overridden for some chart. |
|
* @return {type} description |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.getBaseAxis = function () { |
|
var coordSys = this.coordinateSystem; // @ts-ignore |
|
|
|
return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis(); |
|
}; |
|
/** |
|
* Default tooltip formatter |
|
* |
|
* @param dataIndex |
|
* @param multipleSeries |
|
* @param dataType |
|
* @param renderMode valid values: 'html'(by default) and 'richText'. |
|
* 'html' is used for rendering tooltip in extra DOM form, and the result |
|
* string is used as DOM HTML content. |
|
* 'richText' is used for rendering tooltip in rich text form, for those where |
|
* DOM operation is not supported. |
|
* @return formatted tooltip with `html` and `markers` |
|
* Notice: The override method can also return string |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { |
|
return defaultSeriesFormatTooltip({ |
|
series: this, |
|
dataIndex: dataIndex, |
|
multipleSeries: multipleSeries |
|
}); |
|
}; |
|
|
|
SeriesModel.prototype.isAnimationEnabled = function () { |
|
var ecModel = this.ecModel; // Disable animation if using echarts in node but not give ssr flag. |
|
// In ssr mode, renderToString will generate svg with css animation. |
|
|
|
if (env.node && !(ecModel && ecModel.ssr)) { |
|
return false; |
|
} |
|
|
|
var animationEnabled = this.getShallow('animation'); |
|
|
|
if (animationEnabled) { |
|
if (this.getData().count() > this.getShallow('animationThreshold')) { |
|
animationEnabled = false; |
|
} |
|
} |
|
|
|
return !!animationEnabled; |
|
}; |
|
|
|
SeriesModel.prototype.restoreData = function () { |
|
this.dataTask.dirty(); |
|
}; |
|
|
|
SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) { |
|
var ecModel = this.ecModel; // PENDING |
|
|
|
var color = PaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum); |
|
|
|
if (!color) { |
|
color = ecModel.getColorFromPalette(name, scope, requestColorNum); |
|
} |
|
|
|
return color; |
|
}; |
|
/** |
|
* Use `data.mapDimensionsAll(coordDim)` instead. |
|
* @deprecated |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.coordDimToDataDim = function (coordDim) { |
|
return this.getRawData().mapDimensionsAll(coordDim); |
|
}; |
|
/** |
|
* Get progressive rendering count each step |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.getProgressive = function () { |
|
return this.get('progressive'); |
|
}; |
|
/** |
|
* Get progressive rendering count each step |
|
*/ |
|
|
|
|
|
SeriesModel.prototype.getProgressiveThreshold = function () { |
|
return this.get('progressiveThreshold'); |
|
}; // PENGING If selectedMode is null ? |
|
|
|
|
|
SeriesModel.prototype.select = function (innerDataIndices, dataType) { |
|
this._innerSelect(this.getData(dataType), innerDataIndices); |
|
}; |
|
|
|
SeriesModel.prototype.unselect = function (innerDataIndices, dataType) { |
|
var selectedMap = this.option.selectedMap; |
|
|
|
if (!selectedMap) { |
|
return; |
|
} |
|
|
|
var selectedMode = this.option.selectedMode; |
|
var data = this.getData(dataType); |
|
|
|
if (selectedMode === 'series' || selectedMap === 'all') { |
|
this.option.selectedMap = {}; |
|
this._selectedDataIndicesMap = {}; |
|
return; |
|
} |
|
|
|
for (var i = 0; i < innerDataIndices.length; i++) { |
|
var dataIndex = innerDataIndices[i]; |
|
var nameOrId = getSelectionKey(data, dataIndex); |
|
selectedMap[nameOrId] = false; |
|
this._selectedDataIndicesMap[nameOrId] = -1; |
|
} |
|
}; |
|
|
|
SeriesModel.prototype.toggleSelect = function (innerDataIndices, dataType) { |
|
var tmpArr = []; |
|
|
|
for (var i = 0; i < innerDataIndices.length; i++) { |
|
tmpArr[0] = innerDataIndices[i]; |
|
this.isSelected(innerDataIndices[i], dataType) ? this.unselect(tmpArr, dataType) : this.select(tmpArr, dataType); |
|
} |
|
}; |
|
|
|
SeriesModel.prototype.getSelectedDataIndices = function () { |
|
if (this.option.selectedMap === 'all') { |
|
return [].slice.call(this.getData().getIndices()); |
|
} |
|
|
|
var selectedDataIndicesMap = this._selectedDataIndicesMap; |
|
var nameOrIds = zrUtil.keys(selectedDataIndicesMap); |
|
var dataIndices = []; |
|
|
|
for (var i = 0; i < nameOrIds.length; i++) { |
|
var dataIndex = selectedDataIndicesMap[nameOrIds[i]]; |
|
|
|
if (dataIndex >= 0) { |
|
dataIndices.push(dataIndex); |
|
} |
|
} |
|
|
|
return dataIndices; |
|
}; |
|
|
|
SeriesModel.prototype.isSelected = function (dataIndex, dataType) { |
|
var selectedMap = this.option.selectedMap; |
|
|
|
if (!selectedMap) { |
|
return false; |
|
} |
|
|
|
var data = this.getData(dataType); |
|
return (selectedMap === 'all' || selectedMap[getSelectionKey(data, dataIndex)]) && !data.getItemModel(dataIndex).get(['select', 'disabled']); |
|
}; |
|
|
|
SeriesModel.prototype.isUniversalTransitionEnabled = function () { |
|
if (this[SERIES_UNIVERSAL_TRANSITION_PROP]) { |
|
return true; |
|
} |
|
|
|
var universalTransitionOpt = this.option.universalTransition; // Quick reject |
|
|
|
if (!universalTransitionOpt) { |
|
return false; |
|
} |
|
|
|
if (universalTransitionOpt === true) { |
|
return true; |
|
} // Can be simply 'universalTransition: true' |
|
|
|
|
|
return universalTransitionOpt && universalTransitionOpt.enabled; |
|
}; |
|
|
|
SeriesModel.prototype._innerSelect = function (data, innerDataIndices) { |
|
var _a, _b; |
|
|
|
var option = this.option; |
|
var selectedMode = option.selectedMode; |
|
var len = innerDataIndices.length; |
|
|
|
if (!selectedMode || !len) { |
|
return; |
|
} |
|
|
|
if (selectedMode === 'series') { |
|
option.selectedMap = 'all'; |
|
} else if (selectedMode === 'multiple') { |
|
if (!zrUtil.isObject(option.selectedMap)) { |
|
option.selectedMap = {}; |
|
} |
|
|
|
var selectedMap = option.selectedMap; |
|
|
|
for (var i = 0; i < len; i++) { |
|
var dataIndex = innerDataIndices[i]; // TODO different types of data share same object. |
|
|
|
var nameOrId = getSelectionKey(data, dataIndex); |
|
selectedMap[nameOrId] = true; |
|
this._selectedDataIndicesMap[nameOrId] = data.getRawIndex(dataIndex); |
|
} |
|
} else if (selectedMode === 'single' || selectedMode === true) { |
|
var lastDataIndex = innerDataIndices[len - 1]; |
|
var nameOrId = getSelectionKey(data, lastDataIndex); |
|
option.selectedMap = (_a = {}, _a[nameOrId] = true, _a); |
|
this._selectedDataIndicesMap = (_b = {}, _b[nameOrId] = data.getRawIndex(lastDataIndex), _b); |
|
} |
|
}; |
|
|
|
SeriesModel.prototype._initSelectedMapFromData = function (data) { |
|
// Ignore select info in data if selectedMap exists. |
|
// NOTE It's only for legacy usage. edge data is not supported. |
|
if (this.option.selectedMap) { |
|
return; |
|
} |
|
|
|
var dataIndices = []; |
|
|
|
if (data.hasItemOption) { |
|
data.each(function (idx) { |
|
var rawItem = data.getRawDataItem(idx); |
|
|
|
if (rawItem && rawItem.selected) { |
|
dataIndices.push(idx); |
|
} |
|
}); |
|
} |
|
|
|
if (dataIndices.length > 0) { |
|
this._innerSelect(data, dataIndices); |
|
} |
|
}; // /** |
|
// * @see {module:echarts/stream/Scheduler} |
|
// */ |
|
// abstract pipeTask: null |
|
|
|
|
|
SeriesModel.registerClass = function (clz) { |
|
return ComponentModel.registerClass(clz); |
|
}; |
|
|
|
SeriesModel.protoInitialize = function () { |
|
var proto = SeriesModel.prototype; |
|
proto.type = 'series.__base__'; |
|
proto.seriesIndex = 0; |
|
proto.ignoreStyleOnData = false; |
|
proto.hasSymbolVisual = false; |
|
proto.defaultSymbol = 'circle'; // Make sure the values can be accessed! |
|
|
|
proto.visualStyleAccessPath = 'itemStyle'; |
|
proto.visualDrawType = 'fill'; |
|
}(); |
|
|
|
return SeriesModel; |
|
}(ComponentModel); |
|
|
|
zrUtil.mixin(SeriesModel, DataFormatMixin); |
|
zrUtil.mixin(SeriesModel, PaletteMixin); |
|
mountExtend(SeriesModel, ComponentModel); |
|
/** |
|
* MUST be called after `prepareSource` called |
|
* Here we need to make auto series, especially for auto legend. But we |
|
* do not modify series.name in option to avoid side effects. |
|
*/ |
|
|
|
function autoSeriesName(seriesModel) { |
|
// User specified name has higher priority, otherwise it may cause |
|
// series can not be queried unexpectedly. |
|
var name = seriesModel.name; |
|
|
|
if (!modelUtil.isNameSpecified(seriesModel)) { |
|
seriesModel.name = getSeriesAutoName(seriesModel) || name; |
|
} |
|
} |
|
|
|
function getSeriesAutoName(seriesModel) { |
|
var data = seriesModel.getRawData(); |
|
var dataDims = data.mapDimensionsAll('seriesName'); |
|
var nameArr = []; |
|
zrUtil.each(dataDims, function (dataDim) { |
|
var dimInfo = data.getDimensionInfo(dataDim); |
|
dimInfo.displayName && nameArr.push(dimInfo.displayName); |
|
}); |
|
return nameArr.join(' '); |
|
} |
|
|
|
function dataTaskCount(context) { |
|
return context.model.getRawData().count(); |
|
} |
|
|
|
function dataTaskReset(context) { |
|
var seriesModel = context.model; |
|
seriesModel.setData(seriesModel.getRawData().cloneShallow()); |
|
return dataTaskProgress; |
|
} |
|
|
|
function dataTaskProgress(param, context) { |
|
// Avoid repeat cloneShallow when data just created in reset. |
|
if (context.outputData && param.end > context.outputData.count()) { |
|
context.model.getRawData().cloneShallow(context.outputData); |
|
} |
|
} // TODO refactor |
|
|
|
|
|
function wrapData(data, seriesModel) { |
|
zrUtil.each(zrUtil.concatArray(data.CHANGABLE_METHODS, data.DOWNSAMPLE_METHODS), function (methodName) { |
|
data.wrapMethod(methodName, zrUtil.curry(onDataChange, seriesModel)); |
|
}); |
|
} |
|
|
|
function onDataChange(seriesModel, newList) { |
|
var task = getCurrentTask(seriesModel); |
|
|
|
if (task) { |
|
// Consider case: filter, selectRange |
|
task.setOutputEnd((newList || this).count()); |
|
} |
|
|
|
return newList; |
|
} |
|
|
|
function getCurrentTask(seriesModel) { |
|
var scheduler = (seriesModel.ecModel || {}).scheduler; |
|
var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid); |
|
|
|
if (pipeline) { |
|
// When pipline finished, the currrentTask keep the last |
|
// task (renderTask). |
|
var task = pipeline.currentTask; |
|
|
|
if (task) { |
|
var agentStubMap = task.agentStubMap; |
|
|
|
if (agentStubMap) { |
|
task = agentStubMap.get(seriesModel.uid); |
|
} |
|
} |
|
|
|
return task; |
|
} |
|
} |
|
|
|
export default SeriesModel; |