|
@@ -0,0 +1,748 @@
|
|
|
+
|
|
|
+/*
|
|
|
+* 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";
|
|
|
+/**
|
|
|
+ * Caution: If the mechanism should be changed some day, these cases
|
|
|
+ * should be considered:
|
|
|
+ *
|
|
|
+ * (1) In `merge option` mode, if using the same option to call `setOption`
|
|
|
+ * many times, the result should be the same (try our best to ensure that).
|
|
|
+ * (2) In `merge option` mode, if a component has no id/name specified, it
|
|
|
+ * will be merged by index, and the result sequence of the components is
|
|
|
+ * consistent to the original sequence.
|
|
|
+ * (3) In `replaceMerge` mode, keep the result sequence of the components is
|
|
|
+ * consistent to the original sequence, even though there might result in "hole".
|
|
|
+ * (4) `reset` feature (in toolbox). Find detailed info in comments about
|
|
|
+ * `mergeOption` in module:echarts/model/OptionManager.
|
|
|
+ */
|
|
|
+import { each, filter, isArray, isObject, isString, createHashMap, assert, clone, merge, extend, mixin, isFunction } from 'zrender/lib/core/util.js';
|
|
|
+import * as modelUtil from '../util/model.js';
|
|
|
+import Model from './Model.js';
|
|
|
+import ComponentModel from './Component.js';
|
|
|
+import globalDefault from './globalDefault.js';
|
|
|
+import { resetSourceDefaulter } from '../data/helper/sourceHelper.js';
|
|
|
+import { concatInternalOptions } from './internalComponentCreator.js';
|
|
|
+import { PaletteMixin } from './mixin/palette.js';
|
|
|
+import { error, warn } from '../util/log.js';
|
|
|
+// -----------------------
|
|
|
+// Internal method names:
|
|
|
+// -----------------------
|
|
|
+var reCreateSeriesIndices;
|
|
|
+var assertSeriesInitialized;
|
|
|
+var initBase;
|
|
|
+var OPTION_INNER_KEY = '\0_ec_inner';
|
|
|
+var OPTION_INNER_VALUE = 1;
|
|
|
+var BUITIN_COMPONENTS_MAP = {
|
|
|
+ grid: 'GridComponent',
|
|
|
+ polar: 'PolarComponent',
|
|
|
+ geo: 'GeoComponent',
|
|
|
+ singleAxis: 'SingleAxisComponent',
|
|
|
+ parallel: 'ParallelComponent',
|
|
|
+ calendar: 'CalendarComponent',
|
|
|
+ graphic: 'GraphicComponent',
|
|
|
+ toolbox: 'ToolboxComponent',
|
|
|
+ tooltip: 'TooltipComponent',
|
|
|
+ axisPointer: 'AxisPointerComponent',
|
|
|
+ brush: 'BrushComponent',
|
|
|
+ title: 'TitleComponent',
|
|
|
+ timeline: 'TimelineComponent',
|
|
|
+ markPoint: 'MarkPointComponent',
|
|
|
+ markLine: 'MarkLineComponent',
|
|
|
+ markArea: 'MarkAreaComponent',
|
|
|
+ legend: 'LegendComponent',
|
|
|
+ dataZoom: 'DataZoomComponent',
|
|
|
+ visualMap: 'VisualMapComponent',
|
|
|
+ // aria: 'AriaComponent',
|
|
|
+ // dataset: 'DatasetComponent',
|
|
|
+ // Dependencies
|
|
|
+ xAxis: 'GridComponent',
|
|
|
+ yAxis: 'GridComponent',
|
|
|
+ angleAxis: 'PolarComponent',
|
|
|
+ radiusAxis: 'PolarComponent'
|
|
|
+};
|
|
|
+var BUILTIN_CHARTS_MAP = {
|
|
|
+ line: 'LineChart',
|
|
|
+ bar: 'BarChart',
|
|
|
+ pie: 'PieChart',
|
|
|
+ scatter: 'ScatterChart',
|
|
|
+ radar: 'RadarChart',
|
|
|
+ map: 'MapChart',
|
|
|
+ tree: 'TreeChart',
|
|
|
+ treemap: 'TreemapChart',
|
|
|
+ graph: 'GraphChart',
|
|
|
+ gauge: 'GaugeChart',
|
|
|
+ funnel: 'FunnelChart',
|
|
|
+ parallel: 'ParallelChart',
|
|
|
+ sankey: 'SankeyChart',
|
|
|
+ boxplot: 'BoxplotChart',
|
|
|
+ candlestick: 'CandlestickChart',
|
|
|
+ effectScatter: 'EffectScatterChart',
|
|
|
+ lines: 'LinesChart',
|
|
|
+ heatmap: 'HeatmapChart',
|
|
|
+ pictorialBar: 'PictorialBarChart',
|
|
|
+ themeRiver: 'ThemeRiverChart',
|
|
|
+ sunburst: 'SunburstChart',
|
|
|
+ custom: 'CustomChart'
|
|
|
+};
|
|
|
+var componetsMissingLogPrinted = {};
|
|
|
+function checkMissingComponents(option) {
|
|
|
+ each(option, function (componentOption, mainType) {
|
|
|
+ if (!ComponentModel.hasClass(mainType)) {
|
|
|
+ var componentImportName = BUITIN_COMPONENTS_MAP[mainType];
|
|
|
+ if (componentImportName && !componetsMissingLogPrinted[componentImportName]) {
|
|
|
+ error("Component " + mainType + " is used but not imported.\nimport { " + componentImportName + " } from 'echarts/components';\necharts.use([" + componentImportName + "]);");
|
|
|
+ componetsMissingLogPrinted[componentImportName] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+var GlobalModel = /** @class */function (_super) {
|
|
|
+ __extends(GlobalModel, _super);
|
|
|
+ function GlobalModel() {
|
|
|
+ return _super !== null && _super.apply(this, arguments) || this;
|
|
|
+ }
|
|
|
+ GlobalModel.prototype.init = function (option, parentModel, ecModel, theme, locale, optionManager) {
|
|
|
+ theme = theme || {};
|
|
|
+ this.option = null; // Mark as not initialized.
|
|
|
+ this._theme = new Model(theme);
|
|
|
+ this._locale = new Model(locale);
|
|
|
+ this._optionManager = optionManager;
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.setOption = function (option, opts, optionPreprocessorFuncs) {
|
|
|
+ if (process.env.NODE_ENV !== 'production') {
|
|
|
+ assert(option != null, 'option is null/undefined');
|
|
|
+ assert(option[OPTION_INNER_KEY] !== OPTION_INNER_VALUE, 'please use chart.getOption()');
|
|
|
+ }
|
|
|
+ var innerOpt = normalizeSetOptionInput(opts);
|
|
|
+ this._optionManager.setOption(option, optionPreprocessorFuncs, innerOpt);
|
|
|
+ this._resetOption(null, innerOpt);
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * @param type null/undefined: reset all.
|
|
|
+ * 'recreate': force recreate all.
|
|
|
+ * 'timeline': only reset timeline option
|
|
|
+ * 'media': only reset media query option
|
|
|
+ * @return Whether option changed.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.resetOption = function (type, opt) {
|
|
|
+ return this._resetOption(type, normalizeSetOptionInput(opt));
|
|
|
+ };
|
|
|
+ GlobalModel.prototype._resetOption = function (type, opt) {
|
|
|
+ var optionChanged = false;
|
|
|
+ var optionManager = this._optionManager;
|
|
|
+ if (!type || type === 'recreate') {
|
|
|
+ var baseOption = optionManager.mountOption(type === 'recreate');
|
|
|
+ if (process.env.NODE_ENV !== 'production') {
|
|
|
+ checkMissingComponents(baseOption);
|
|
|
+ }
|
|
|
+ if (!this.option || type === 'recreate') {
|
|
|
+ initBase(this, baseOption);
|
|
|
+ } else {
|
|
|
+ this.restoreData();
|
|
|
+ this._mergeOption(baseOption, opt);
|
|
|
+ }
|
|
|
+ optionChanged = true;
|
|
|
+ }
|
|
|
+ if (type === 'timeline' || type === 'media') {
|
|
|
+ this.restoreData();
|
|
|
+ }
|
|
|
+ // By design, if `setOption(option2)` at the second time, and `option2` is a `ECUnitOption`,
|
|
|
+ // it should better not have the same props with `MediaUnit['option']`.
|
|
|
+ // Because either `option2` or `MediaUnit['option']` will be always merged to "current option"
|
|
|
+ // rather than original "baseOption". If they both override a prop, the result might be
|
|
|
+ // unexpected when media state changed after `setOption` called.
|
|
|
+ // If we really need to modify a props in each `MediaUnit['option']`, use the full version
|
|
|
+ // (`{baseOption, media}`) in `setOption`.
|
|
|
+ // For `timeline`, the case is the same.
|
|
|
+ if (!type || type === 'recreate' || type === 'timeline') {
|
|
|
+ var timelineOption = optionManager.getTimelineOption(this);
|
|
|
+ if (timelineOption) {
|
|
|
+ optionChanged = true;
|
|
|
+ this._mergeOption(timelineOption, opt);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!type || type === 'recreate' || type === 'media') {
|
|
|
+ var mediaOptions = optionManager.getMediaOption(this);
|
|
|
+ if (mediaOptions.length) {
|
|
|
+ each(mediaOptions, function (mediaOption) {
|
|
|
+ optionChanged = true;
|
|
|
+ this._mergeOption(mediaOption, opt);
|
|
|
+ }, this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return optionChanged;
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.mergeOption = function (option) {
|
|
|
+ this._mergeOption(option, null);
|
|
|
+ };
|
|
|
+ GlobalModel.prototype._mergeOption = function (newOption, opt) {
|
|
|
+ var option = this.option;
|
|
|
+ var componentsMap = this._componentsMap;
|
|
|
+ var componentsCount = this._componentsCount;
|
|
|
+ var newCmptTypes = [];
|
|
|
+ var newCmptTypeMap = createHashMap();
|
|
|
+ var replaceMergeMainTypeMap = opt && opt.replaceMergeMainTypeMap;
|
|
|
+ resetSourceDefaulter(this);
|
|
|
+ // If no component class, merge directly.
|
|
|
+ // For example: color, animaiton options, etc.
|
|
|
+ each(newOption, function (componentOption, mainType) {
|
|
|
+ if (componentOption == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!ComponentModel.hasClass(mainType)) {
|
|
|
+ // globalSettingTask.dirty();
|
|
|
+ option[mainType] = option[mainType] == null ? clone(componentOption) : merge(option[mainType], componentOption, true);
|
|
|
+ } else if (mainType) {
|
|
|
+ newCmptTypes.push(mainType);
|
|
|
+ newCmptTypeMap.set(mainType, true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (replaceMergeMainTypeMap) {
|
|
|
+ // If there is a mainType `xxx` in `replaceMerge` but not declared in option,
|
|
|
+ // we trade it as it is declared in option as `{xxx: []}`. Because:
|
|
|
+ // (1) for normal merge, `{xxx: null/undefined}` are the same meaning as `{xxx: []}`.
|
|
|
+ // (2) some preprocessor may convert some of `{xxx: null/undefined}` to `{xxx: []}`.
|
|
|
+ replaceMergeMainTypeMap.each(function (val, mainTypeInReplaceMerge) {
|
|
|
+ if (ComponentModel.hasClass(mainTypeInReplaceMerge) && !newCmptTypeMap.get(mainTypeInReplaceMerge)) {
|
|
|
+ newCmptTypes.push(mainTypeInReplaceMerge);
|
|
|
+ newCmptTypeMap.set(mainTypeInReplaceMerge, true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ ComponentModel.topologicalTravel(newCmptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this);
|
|
|
+ function visitComponent(mainType) {
|
|
|
+ var newCmptOptionList = concatInternalOptions(this, mainType, modelUtil.normalizeToArray(newOption[mainType]));
|
|
|
+ var oldCmptList = componentsMap.get(mainType);
|
|
|
+ var mergeMode =
|
|
|
+ // `!oldCmptList` means init. See the comment in `mappingToExists`
|
|
|
+ !oldCmptList ? 'replaceAll' : replaceMergeMainTypeMap && replaceMergeMainTypeMap.get(mainType) ? 'replaceMerge' : 'normalMerge';
|
|
|
+ var mappingResult = modelUtil.mappingToExists(oldCmptList, newCmptOptionList, mergeMode);
|
|
|
+ // Set mainType and complete subType.
|
|
|
+ modelUtil.setComponentTypeToKeyInfo(mappingResult, mainType, ComponentModel);
|
|
|
+ // Empty it before the travel, in order to prevent `this._componentsMap`
|
|
|
+ // from being used in the `init`/`mergeOption`/`optionUpdated` of some
|
|
|
+ // components, which is probably incorrect logic.
|
|
|
+ option[mainType] = null;
|
|
|
+ componentsMap.set(mainType, null);
|
|
|
+ componentsCount.set(mainType, 0);
|
|
|
+ var optionsByMainType = [];
|
|
|
+ var cmptsByMainType = [];
|
|
|
+ var cmptsCountByMainType = 0;
|
|
|
+ var tooltipExists;
|
|
|
+ var tooltipWarningLogged;
|
|
|
+ each(mappingResult, function (resultItem, index) {
|
|
|
+ var componentModel = resultItem.existing;
|
|
|
+ var newCmptOption = resultItem.newOption;
|
|
|
+ if (!newCmptOption) {
|
|
|
+ if (componentModel) {
|
|
|
+ // Consider where is no new option and should be merged using {},
|
|
|
+ // see removeEdgeAndAdd in topologicalTravel and
|
|
|
+ // ComponentModel.getAllClassMainTypes.
|
|
|
+ componentModel.mergeOption({}, this);
|
|
|
+ componentModel.optionUpdated({}, false);
|
|
|
+ }
|
|
|
+ // If no both `resultItem.exist` and `resultItem.option`,
|
|
|
+ // either it is in `replaceMerge` and not matched by any id,
|
|
|
+ // or it has been removed in previous `replaceMerge` and left a "hole" in this component index.
|
|
|
+ } else {
|
|
|
+ var isSeriesType = mainType === 'series';
|
|
|
+ var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, !isSeriesType // Give a more detailed warn later if series don't exists
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!ComponentModelClass) {
|
|
|
+ if (process.env.NODE_ENV !== 'production') {
|
|
|
+ var subType = resultItem.keyInfo.subType;
|
|
|
+ var seriesImportName = BUILTIN_CHARTS_MAP[subType];
|
|
|
+ if (!componetsMissingLogPrinted[subType]) {
|
|
|
+ componetsMissingLogPrinted[subType] = true;
|
|
|
+ if (seriesImportName) {
|
|
|
+ error("Series " + subType + " is used but not imported.\nimport { " + seriesImportName + " } from 'echarts/charts';\necharts.use([" + seriesImportName + "]);");
|
|
|
+ } else {
|
|
|
+ error("Unknown series " + subType);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // TODO Before multiple tooltips get supported, we do this check to avoid unexpected exception.
|
|
|
+ if (mainType === 'tooltip') {
|
|
|
+ if (tooltipExists) {
|
|
|
+ if (process.env.NODE_ENV !== 'production') {
|
|
|
+ if (!tooltipWarningLogged) {
|
|
|
+ warn('Currently only one tooltip component is allowed.');
|
|
|
+ tooltipWarningLogged = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ tooltipExists = true;
|
|
|
+ }
|
|
|
+ if (componentModel && componentModel.constructor === ComponentModelClass) {
|
|
|
+ componentModel.name = resultItem.keyInfo.name;
|
|
|
+ // componentModel.settingTask && componentModel.settingTask.dirty();
|
|
|
+ componentModel.mergeOption(newCmptOption, this);
|
|
|
+ componentModel.optionUpdated(newCmptOption, false);
|
|
|
+ } else {
|
|
|
+ // PENDING Global as parent ?
|
|
|
+ var extraOpt = extend({
|
|
|
+ componentIndex: index
|
|
|
+ }, resultItem.keyInfo);
|
|
|
+ componentModel = new ComponentModelClass(newCmptOption, this, this, extraOpt);
|
|
|
+ // Assign `keyInfo`
|
|
|
+ extend(componentModel, extraOpt);
|
|
|
+ if (resultItem.brandNew) {
|
|
|
+ componentModel.__requireNewView = true;
|
|
|
+ }
|
|
|
+ componentModel.init(newCmptOption, this, this);
|
|
|
+ // Call optionUpdated after init.
|
|
|
+ // newCmptOption has been used as componentModel.option
|
|
|
+ // and may be merged with theme and default, so pass null
|
|
|
+ // to avoid confusion.
|
|
|
+ componentModel.optionUpdated(null, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (componentModel) {
|
|
|
+ optionsByMainType.push(componentModel.option);
|
|
|
+ cmptsByMainType.push(componentModel);
|
|
|
+ cmptsCountByMainType++;
|
|
|
+ } else {
|
|
|
+ // Always do assign to avoid elided item in array.
|
|
|
+ optionsByMainType.push(void 0);
|
|
|
+ cmptsByMainType.push(void 0);
|
|
|
+ }
|
|
|
+ }, this);
|
|
|
+ option[mainType] = optionsByMainType;
|
|
|
+ componentsMap.set(mainType, cmptsByMainType);
|
|
|
+ componentsCount.set(mainType, cmptsCountByMainType);
|
|
|
+ // Backup series for filtering.
|
|
|
+ if (mainType === 'series') {
|
|
|
+ reCreateSeriesIndices(this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // If no series declared, ensure `_seriesIndices` initialized.
|
|
|
+ if (!this._seriesIndices) {
|
|
|
+ reCreateSeriesIndices(this);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Get option for output (cloned option and inner info removed)
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.getOption = function () {
|
|
|
+ var option = clone(this.option);
|
|
|
+ each(option, function (optInMainType, mainType) {
|
|
|
+ if (ComponentModel.hasClass(mainType)) {
|
|
|
+ var opts = modelUtil.normalizeToArray(optInMainType);
|
|
|
+ // Inner cmpts need to be removed.
|
|
|
+ // Inner cmpts might not be at last since ec5.0, but still
|
|
|
+ // compatible for users: if inner cmpt at last, splice the returned array.
|
|
|
+ var realLen = opts.length;
|
|
|
+ var metNonInner = false;
|
|
|
+ for (var i = realLen - 1; i >= 0; i--) {
|
|
|
+ // Remove options with inner id.
|
|
|
+ if (opts[i] && !modelUtil.isComponentIdInternal(opts[i])) {
|
|
|
+ metNonInner = true;
|
|
|
+ } else {
|
|
|
+ opts[i] = null;
|
|
|
+ !metNonInner && realLen--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ opts.length = realLen;
|
|
|
+ option[mainType] = opts;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ delete option[OPTION_INNER_KEY];
|
|
|
+ return option;
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.getTheme = function () {
|
|
|
+ return this._theme;
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.getLocaleModel = function () {
|
|
|
+ return this._locale;
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.setUpdatePayload = function (payload) {
|
|
|
+ this._payload = payload;
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.getUpdatePayload = function () {
|
|
|
+ return this._payload;
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * @param idx If not specified, return the first one.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.getComponent = function (mainType, idx) {
|
|
|
+ var list = this._componentsMap.get(mainType);
|
|
|
+ if (list) {
|
|
|
+ var cmpt = list[idx || 0];
|
|
|
+ if (cmpt) {
|
|
|
+ return cmpt;
|
|
|
+ } else if (idx == null) {
|
|
|
+ for (var i = 0; i < list.length; i++) {
|
|
|
+ if (list[i]) {
|
|
|
+ return list[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * @return Never be null/undefined.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.queryComponents = function (condition) {
|
|
|
+ var mainType = condition.mainType;
|
|
|
+ if (!mainType) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ var index = condition.index;
|
|
|
+ var id = condition.id;
|
|
|
+ var name = condition.name;
|
|
|
+ var cmpts = this._componentsMap.get(mainType);
|
|
|
+ if (!cmpts || !cmpts.length) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ var result;
|
|
|
+ if (index != null) {
|
|
|
+ result = [];
|
|
|
+ each(modelUtil.normalizeToArray(index), function (idx) {
|
|
|
+ cmpts[idx] && result.push(cmpts[idx]);
|
|
|
+ });
|
|
|
+ } else if (id != null) {
|
|
|
+ result = queryByIdOrName('id', id, cmpts);
|
|
|
+ } else if (name != null) {
|
|
|
+ result = queryByIdOrName('name', name, cmpts);
|
|
|
+ } else {
|
|
|
+ // Return all non-empty components in that mainType
|
|
|
+ result = filter(cmpts, function (cmpt) {
|
|
|
+ return !!cmpt;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return filterBySubType(result, condition);
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * The interface is different from queryComponents,
|
|
|
+ * which is convenient for inner usage.
|
|
|
+ *
|
|
|
+ * @usage
|
|
|
+ * let result = findComponents(
|
|
|
+ * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}
|
|
|
+ * );
|
|
|
+ * let result = findComponents(
|
|
|
+ * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}
|
|
|
+ * );
|
|
|
+ * let result = findComponents(
|
|
|
+ * {mainType: 'series',
|
|
|
+ * filter: function (model, index) {...}}
|
|
|
+ * );
|
|
|
+ * // result like [component0, componnet1, ...]
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.findComponents = function (condition) {
|
|
|
+ var query = condition.query;
|
|
|
+ var mainType = condition.mainType;
|
|
|
+ var queryCond = getQueryCond(query);
|
|
|
+ var result = queryCond ? this.queryComponents(queryCond)
|
|
|
+ // Retrieve all non-empty components.
|
|
|
+ : filter(this._componentsMap.get(mainType), function (cmpt) {
|
|
|
+ return !!cmpt;
|
|
|
+ });
|
|
|
+ return doFilter(filterBySubType(result, condition));
|
|
|
+ function getQueryCond(q) {
|
|
|
+ var indexAttr = mainType + 'Index';
|
|
|
+ var idAttr = mainType + 'Id';
|
|
|
+ var nameAttr = mainType + 'Name';
|
|
|
+ return q && (q[indexAttr] != null || q[idAttr] != null || q[nameAttr] != null) ? {
|
|
|
+ mainType: mainType,
|
|
|
+ // subType will be filtered finally.
|
|
|
+ index: q[indexAttr],
|
|
|
+ id: q[idAttr],
|
|
|
+ name: q[nameAttr]
|
|
|
+ } : null;
|
|
|
+ }
|
|
|
+ function doFilter(res) {
|
|
|
+ return condition.filter ? filter(res, condition.filter) : res;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.eachComponent = function (mainType, cb, context) {
|
|
|
+ var componentsMap = this._componentsMap;
|
|
|
+ if (isFunction(mainType)) {
|
|
|
+ var ctxForAll_1 = cb;
|
|
|
+ var cbForAll_1 = mainType;
|
|
|
+ componentsMap.each(function (cmpts, componentType) {
|
|
|
+ for (var i = 0; cmpts && i < cmpts.length; i++) {
|
|
|
+ var cmpt = cmpts[i];
|
|
|
+ cmpt && cbForAll_1.call(ctxForAll_1, componentType, cmpt, cmpt.componentIndex);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ var cmpts = isString(mainType) ? componentsMap.get(mainType) : isObject(mainType) ? this.findComponents(mainType) : null;
|
|
|
+ for (var i = 0; cmpts && i < cmpts.length; i++) {
|
|
|
+ var cmpt = cmpts[i];
|
|
|
+ cmpt && cb.call(context, cmpt, cmpt.componentIndex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Get series list before filtered by name.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.getSeriesByName = function (name) {
|
|
|
+ var nameStr = modelUtil.convertOptionIdName(name, null);
|
|
|
+ return filter(this._componentsMap.get('series'), function (oneSeries) {
|
|
|
+ return !!oneSeries && nameStr != null && oneSeries.name === nameStr;
|
|
|
+ });
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Get series list before filtered by index.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.getSeriesByIndex = function (seriesIndex) {
|
|
|
+ return this._componentsMap.get('series')[seriesIndex];
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Get series list before filtered by type.
|
|
|
+ * FIXME: rename to getRawSeriesByType?
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.getSeriesByType = function (subType) {
|
|
|
+ return filter(this._componentsMap.get('series'), function (oneSeries) {
|
|
|
+ return !!oneSeries && oneSeries.subType === subType;
|
|
|
+ });
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Get all series before filtered.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.getSeries = function () {
|
|
|
+ return filter(this._componentsMap.get('series'), function (oneSeries) {
|
|
|
+ return !!oneSeries;
|
|
|
+ });
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Count series before filtered.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.getSeriesCount = function () {
|
|
|
+ return this._componentsCount.get('series');
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * After filtering, series may be different
|
|
|
+ * from raw series.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.eachSeries = function (cb, context) {
|
|
|
+ assertSeriesInitialized(this);
|
|
|
+ each(this._seriesIndices, function (rawSeriesIndex) {
|
|
|
+ var series = this._componentsMap.get('series')[rawSeriesIndex];
|
|
|
+ cb.call(context, series, rawSeriesIndex);
|
|
|
+ }, this);
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Iterate raw series before filtered.
|
|
|
+ *
|
|
|
+ * @param {Function} cb
|
|
|
+ * @param {*} context
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.eachRawSeries = function (cb, context) {
|
|
|
+ each(this._componentsMap.get('series'), function (series) {
|
|
|
+ series && cb.call(context, series, series.componentIndex);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * After filtering, series may be different.
|
|
|
+ * from raw series.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.eachSeriesByType = function (subType, cb, context) {
|
|
|
+ assertSeriesInitialized(this);
|
|
|
+ each(this._seriesIndices, function (rawSeriesIndex) {
|
|
|
+ var series = this._componentsMap.get('series')[rawSeriesIndex];
|
|
|
+ if (series.subType === subType) {
|
|
|
+ cb.call(context, series, rawSeriesIndex);
|
|
|
+ }
|
|
|
+ }, this);
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * Iterate raw series before filtered of given type.
|
|
|
+ */
|
|
|
+ GlobalModel.prototype.eachRawSeriesByType = function (subType, cb, context) {
|
|
|
+ return each(this.getSeriesByType(subType), cb, context);
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.isSeriesFiltered = function (seriesModel) {
|
|
|
+ assertSeriesInitialized(this);
|
|
|
+ return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.getCurrentSeriesIndices = function () {
|
|
|
+ return (this._seriesIndices || []).slice();
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.filterSeries = function (cb, context) {
|
|
|
+ assertSeriesInitialized(this);
|
|
|
+ var newSeriesIndices = [];
|
|
|
+ each(this._seriesIndices, function (seriesRawIdx) {
|
|
|
+ var series = this._componentsMap.get('series')[seriesRawIdx];
|
|
|
+ cb.call(context, series, seriesRawIdx) && newSeriesIndices.push(seriesRawIdx);
|
|
|
+ }, this);
|
|
|
+ this._seriesIndices = newSeriesIndices;
|
|
|
+ this._seriesIndicesMap = createHashMap(newSeriesIndices);
|
|
|
+ };
|
|
|
+ GlobalModel.prototype.restoreData = function (payload) {
|
|
|
+ reCreateSeriesIndices(this);
|
|
|
+ var componentsMap = this._componentsMap;
|
|
|
+ var componentTypes = [];
|
|
|
+ componentsMap.each(function (components, componentType) {
|
|
|
+ if (ComponentModel.hasClass(componentType)) {
|
|
|
+ componentTypes.push(componentType);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType) {
|
|
|
+ each(componentsMap.get(componentType), function (component) {
|
|
|
+ if (component && (componentType !== 'series' || !isNotTargetSeries(component, payload))) {
|
|
|
+ component.restoreData();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
+ GlobalModel.internalField = function () {
|
|
|
+ reCreateSeriesIndices = function (ecModel) {
|
|
|
+ var seriesIndices = ecModel._seriesIndices = [];
|
|
|
+ each(ecModel._componentsMap.get('series'), function (series) {
|
|
|
+ // series may have been removed by `replaceMerge`.
|
|
|
+ series && seriesIndices.push(series.componentIndex);
|
|
|
+ });
|
|
|
+ ecModel._seriesIndicesMap = createHashMap(seriesIndices);
|
|
|
+ };
|
|
|
+ assertSeriesInitialized = function (ecModel) {
|
|
|
+ // Components that use _seriesIndices should depends on series component,
|
|
|
+ // which make sure that their initialization is after series.
|
|
|
+ if (process.env.NODE_ENV !== 'production') {
|
|
|
+ if (!ecModel._seriesIndices) {
|
|
|
+ throw new Error('Option should contains series.');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ initBase = function (ecModel, baseOption) {
|
|
|
+ // Using OPTION_INNER_KEY to mark that this option cannot be used outside,
|
|
|
+ // i.e. `chart.setOption(chart.getModel().option);` is forbidden.
|
|
|
+ ecModel.option = {};
|
|
|
+ ecModel.option[OPTION_INNER_KEY] = OPTION_INNER_VALUE;
|
|
|
+ // Init with series: [], in case of calling findSeries method
|
|
|
+ // before series initialized.
|
|
|
+ ecModel._componentsMap = createHashMap({
|
|
|
+ series: []
|
|
|
+ });
|
|
|
+ ecModel._componentsCount = createHashMap();
|
|
|
+ // If user spefied `option.aria`, aria will be enable. This detection should be
|
|
|
+ // performed before theme and globalDefault merge.
|
|
|
+ var airaOption = baseOption.aria;
|
|
|
+ if (isObject(airaOption) && airaOption.enabled == null) {
|
|
|
+ airaOption.enabled = true;
|
|
|
+ }
|
|
|
+ mergeTheme(baseOption, ecModel._theme.option);
|
|
|
+ // TODO Needs clone when merging to the unexisted property
|
|
|
+ merge(baseOption, globalDefault, false);
|
|
|
+ ecModel._mergeOption(baseOption, null);
|
|
|
+ };
|
|
|
+ }();
|
|
|
+ return GlobalModel;
|
|
|
+}(Model);
|
|
|
+function isNotTargetSeries(seriesModel, payload) {
|
|
|
+ if (payload) {
|
|
|
+ var index = payload.seriesIndex;
|
|
|
+ var id = payload.seriesId;
|
|
|
+ var name_1 = payload.seriesName;
|
|
|
+ return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name_1 != null && seriesModel.name !== name_1;
|
|
|
+ }
|
|
|
+}
|
|
|
+function mergeTheme(option, theme) {
|
|
|
+ // PENDING
|
|
|
+ // NOT use `colorLayer` in theme if option has `color`
|
|
|
+ var notMergeColorLayer = option.color && !option.colorLayer;
|
|
|
+ each(theme, function (themeItem, name) {
|
|
|
+ if (name === 'colorLayer' && notMergeColorLayer) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // If it is component model mainType, the model handles that merge later.
|
|
|
+ // otherwise, merge them here.
|
|
|
+ if (!ComponentModel.hasClass(name)) {
|
|
|
+ if (typeof themeItem === 'object') {
|
|
|
+ option[name] = !option[name] ? clone(themeItem) : merge(option[name], themeItem, false);
|
|
|
+ } else {
|
|
|
+ if (option[name] == null) {
|
|
|
+ option[name] = themeItem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+function queryByIdOrName(attr, idOrName, cmpts) {
|
|
|
+ // Here is a break from echarts4: string and number are
|
|
|
+ // treated as equal.
|
|
|
+ if (isArray(idOrName)) {
|
|
|
+ var keyMap_1 = createHashMap();
|
|
|
+ each(idOrName, function (idOrNameItem) {
|
|
|
+ if (idOrNameItem != null) {
|
|
|
+ var idName = modelUtil.convertOptionIdName(idOrNameItem, null);
|
|
|
+ idName != null && keyMap_1.set(idOrNameItem, true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return filter(cmpts, function (cmpt) {
|
|
|
+ return cmpt && keyMap_1.get(cmpt[attr]);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ var idName_1 = modelUtil.convertOptionIdName(idOrName, null);
|
|
|
+ return filter(cmpts, function (cmpt) {
|
|
|
+ return cmpt && idName_1 != null && cmpt[attr] === idName_1;
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+function filterBySubType(components, condition) {
|
|
|
+ // Using hasOwnProperty for restrict. Consider
|
|
|
+ // subType is undefined in user payload.
|
|
|
+ return condition.hasOwnProperty('subType') ? filter(components, function (cmpt) {
|
|
|
+ return cmpt && cmpt.subType === condition.subType;
|
|
|
+ }) : components;
|
|
|
+}
|
|
|
+function normalizeSetOptionInput(opts) {
|
|
|
+ var replaceMergeMainTypeMap = createHashMap();
|
|
|
+ opts && each(modelUtil.normalizeToArray(opts.replaceMerge), function (mainType) {
|
|
|
+ if (process.env.NODE_ENV !== 'production') {
|
|
|
+ assert(ComponentModel.hasClass(mainType), '"' + mainType + '" is not valid component main type in "replaceMerge"');
|
|
|
+ }
|
|
|
+ replaceMergeMainTypeMap.set(mainType, true);
|
|
|
+ });
|
|
|
+ return {
|
|
|
+ replaceMergeMainTypeMap: replaceMergeMainTypeMap
|
|
|
+ };
|
|
|
+}
|
|
|
+mixin(GlobalModel, PaletteMixin);
|
|
|
+export default GlobalModel;
|