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.
		
		
		
		
		
			
		
			
				
					
					
						
							725 lines
						
					
					
						
							22 KiB
						
					
					
				
			
		
		
	
	
							725 lines
						
					
					
						
							22 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. | 
						|
*/ | 
						|
 | 
						|
var _config = require("../config"); | 
						|
 | 
						|
var __DEV__ = _config.__DEV__; | 
						|
 | 
						|
var _util = require("zrender/lib/core/util"); | 
						|
 | 
						|
var each = _util.each; | 
						|
var filter = _util.filter; | 
						|
var map = _util.map; | 
						|
var isArray = _util.isArray; | 
						|
var indexOf = _util.indexOf; | 
						|
var isObject = _util.isObject; | 
						|
var isString = _util.isString; | 
						|
var createHashMap = _util.createHashMap; | 
						|
var assert = _util.assert; | 
						|
var clone = _util.clone; | 
						|
var merge = _util.merge; | 
						|
var extend = _util.extend; | 
						|
var mixin = _util.mixin; | 
						|
 | 
						|
var modelUtil = require("../util/model"); | 
						|
 | 
						|
var Model = require("./Model"); | 
						|
 | 
						|
var ComponentModel = require("./Component"); | 
						|
 | 
						|
var globalDefault = require("./globalDefault"); | 
						|
 | 
						|
var colorPaletteMixin = require("./mixin/colorPalette"); | 
						|
 | 
						|
var _sourceHelper = require("../data/helper/sourceHelper"); | 
						|
 | 
						|
var resetSourceDefaulter = _sourceHelper.resetSourceDefaulter; | 
						|
 | 
						|
/* | 
						|
* 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. | 
						|
*/ | 
						|
 | 
						|
/** | 
						|
 * ECharts global model | 
						|
 * | 
						|
 * @module {echarts/model/Global} | 
						|
 */ | 
						|
 | 
						|
/** | 
						|
 * 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) `reset` feature (in toolbox). Find detailed info in comments about | 
						|
 * `mergeOption` in module:echarts/model/OptionManager. | 
						|
 */ | 
						|
var OPTION_INNER_KEY = '\0_ec_inner'; | 
						|
/** | 
						|
 * @alias module:echarts/model/Global | 
						|
 * | 
						|
 * @param {Object} option | 
						|
 * @param {module:echarts/model/Model} parentModel | 
						|
 * @param {Object} theme | 
						|
 */ | 
						|
 | 
						|
var GlobalModel = Model.extend({ | 
						|
  init: function (option, parentModel, theme, optionManager) { | 
						|
    theme = theme || {}; | 
						|
    this.option = null; // Mark as not initialized. | 
						|
 | 
						|
    /** | 
						|
     * @type {module:echarts/model/Model} | 
						|
     * @private | 
						|
     */ | 
						|
 | 
						|
    this._theme = new Model(theme); | 
						|
    /** | 
						|
     * @type {module:echarts/model/OptionManager} | 
						|
     */ | 
						|
 | 
						|
    this._optionManager = optionManager; | 
						|
  }, | 
						|
  setOption: function (option, optionPreprocessorFuncs) { | 
						|
    assert(!(OPTION_INNER_KEY in option), 'please use chart.getOption()'); | 
						|
 | 
						|
    this._optionManager.setOption(option, optionPreprocessorFuncs); | 
						|
 | 
						|
    this.resetOption(null); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @param {string} type null/undefined: reset all. | 
						|
   *                      'recreate': force recreate all. | 
						|
   *                      'timeline': only reset timeline option | 
						|
   *                      'media': only reset media query option | 
						|
   * @return {boolean} Whether option changed. | 
						|
   */ | 
						|
  resetOption: function (type) { | 
						|
    var optionChanged = false; | 
						|
    var optionManager = this._optionManager; | 
						|
 | 
						|
    if (!type || type === 'recreate') { | 
						|
      var baseOption = optionManager.mountOption(type === 'recreate'); | 
						|
 | 
						|
      if (!this.option || type === 'recreate') { | 
						|
        initBase.call(this, baseOption); | 
						|
      } else { | 
						|
        this.restoreData(); | 
						|
        this.mergeOption(baseOption); | 
						|
      } | 
						|
 | 
						|
      optionChanged = true; | 
						|
    } | 
						|
 | 
						|
    if (type === 'timeline' || type === 'media') { | 
						|
      this.restoreData(); | 
						|
    } | 
						|
 | 
						|
    if (!type || type === 'recreate' || type === 'timeline') { | 
						|
      var timelineOption = optionManager.getTimelineOption(this); | 
						|
      timelineOption && (this.mergeOption(timelineOption), optionChanged = true); | 
						|
    } | 
						|
 | 
						|
    if (!type || type === 'recreate' || type === 'media') { | 
						|
      var mediaOptions = optionManager.getMediaOption(this, this._api); | 
						|
 | 
						|
      if (mediaOptions.length) { | 
						|
        each(mediaOptions, function (mediaOption) { | 
						|
          this.mergeOption(mediaOption, optionChanged = true); | 
						|
        }, this); | 
						|
      } | 
						|
    } | 
						|
 | 
						|
    return optionChanged; | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @protected | 
						|
   */ | 
						|
  mergeOption: function (newOption) { | 
						|
    var option = this.option; | 
						|
    var componentsMap = this._componentsMap; | 
						|
    var newCptTypes = []; | 
						|
    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) { | 
						|
        newCptTypes.push(mainType); | 
						|
      } | 
						|
    }); | 
						|
    ComponentModel.topologicalTravel(newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this); | 
						|
 | 
						|
    function visitComponent(mainType, dependencies) { | 
						|
      var newCptOptionList = modelUtil.normalizeToArray(newOption[mainType]); | 
						|
      var mapResult = modelUtil.mappingToExists(componentsMap.get(mainType), newCptOptionList); | 
						|
      modelUtil.makeIdAndName(mapResult); // Set mainType and complete subType. | 
						|
 | 
						|
      each(mapResult, function (item, index) { | 
						|
        var opt = item.option; | 
						|
 | 
						|
        if (isObject(opt)) { | 
						|
          item.keyInfo.mainType = mainType; | 
						|
          item.keyInfo.subType = determineSubType(mainType, opt, item.exist); | 
						|
        } | 
						|
      }); | 
						|
      var dependentModels = getComponentsByTypes(componentsMap, dependencies); | 
						|
      option[mainType] = []; | 
						|
      componentsMap.set(mainType, []); | 
						|
      each(mapResult, function (resultItem, index) { | 
						|
        var componentModel = resultItem.exist; | 
						|
        var newCptOption = resultItem.option; | 
						|
        assert(isObject(newCptOption) || componentModel, 'Empty component definition'); // Consider where is no new option and should be merged using {}, | 
						|
        // see removeEdgeAndAdd in topologicalTravel and | 
						|
        // ComponentModel.getAllClassMainTypes. | 
						|
 | 
						|
        if (!newCptOption) { | 
						|
          componentModel.mergeOption({}, this); | 
						|
          componentModel.optionUpdated({}, false); | 
						|
        } else { | 
						|
          var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, true); | 
						|
 | 
						|
          if (componentModel && componentModel instanceof ComponentModelClass) { | 
						|
            componentModel.name = resultItem.keyInfo.name; // componentModel.settingTask && componentModel.settingTask.dirty(); | 
						|
 | 
						|
            componentModel.mergeOption(newCptOption, this); | 
						|
            componentModel.optionUpdated(newCptOption, false); | 
						|
          } else { | 
						|
            // PENDING Global as parent ? | 
						|
            var extraOpt = extend({ | 
						|
              dependentModels: dependentModels, | 
						|
              componentIndex: index | 
						|
            }, resultItem.keyInfo); | 
						|
            componentModel = new ComponentModelClass(newCptOption, this, this, extraOpt); | 
						|
            extend(componentModel, extraOpt); | 
						|
            componentModel.init(newCptOption, this, this, extraOpt); // Call optionUpdated after init. | 
						|
            // newCptOption has been used as componentModel.option | 
						|
            // and may be merged with theme and default, so pass null | 
						|
            // to avoid confusion. | 
						|
 | 
						|
            componentModel.optionUpdated(null, true); | 
						|
          } | 
						|
        } | 
						|
 | 
						|
        componentsMap.get(mainType)[index] = componentModel; | 
						|
        option[mainType][index] = componentModel.option; | 
						|
      }, this); // Backup series for filtering. | 
						|
 | 
						|
      if (mainType === 'series') { | 
						|
        createSeriesIndices(this, componentsMap.get('series')); | 
						|
      } | 
						|
    } | 
						|
 | 
						|
    this._seriesIndicesMap = createHashMap(this._seriesIndices = this._seriesIndices || []); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * Get option for output (cloned option and inner info removed) | 
						|
   * @public | 
						|
   * @return {Object} | 
						|
   */ | 
						|
  getOption: function () { | 
						|
    var option = clone(this.option); | 
						|
    each(option, function (opts, mainType) { | 
						|
      if (ComponentModel.hasClass(mainType)) { | 
						|
        var opts = modelUtil.normalizeToArray(opts); | 
						|
 | 
						|
        for (var i = opts.length - 1; i >= 0; i--) { | 
						|
          // Remove options with inner id. | 
						|
          if (modelUtil.isIdInner(opts[i])) { | 
						|
            opts.splice(i, 1); | 
						|
          } | 
						|
        } | 
						|
 | 
						|
        option[mainType] = opts; | 
						|
      } | 
						|
    }); | 
						|
    delete option[OPTION_INNER_KEY]; | 
						|
    return option; | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @return {module:echarts/model/Model} | 
						|
   */ | 
						|
  getTheme: function () { | 
						|
    return this._theme; | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @param {string} mainType | 
						|
   * @param {number} [idx=0] | 
						|
   * @return {module:echarts/model/Component} | 
						|
   */ | 
						|
  getComponent: function (mainType, idx) { | 
						|
    var list = this._componentsMap.get(mainType); | 
						|
 | 
						|
    if (list) { | 
						|
      return list[idx || 0]; | 
						|
    } | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * If none of index and id and name used, return all components with mainType. | 
						|
   * @param {Object} condition | 
						|
   * @param {string} condition.mainType | 
						|
   * @param {string} [condition.subType] If ignore, only query by mainType | 
						|
   * @param {number|Array.<number>} [condition.index] Either input index or id or name. | 
						|
   * @param {string|Array.<string>} [condition.id] Either input index or id or name. | 
						|
   * @param {string|Array.<string>} [condition.name] Either input index or id or name. | 
						|
   * @return {Array.<module:echarts/model/Component>} | 
						|
   */ | 
						|
  queryComponents: function (condition) { | 
						|
    var mainType = condition.mainType; | 
						|
 | 
						|
    if (!mainType) { | 
						|
      return []; | 
						|
    } | 
						|
 | 
						|
    var index = condition.index; | 
						|
    var id = condition.id; | 
						|
    var name = condition.name; | 
						|
 | 
						|
    var cpts = this._componentsMap.get(mainType); | 
						|
 | 
						|
    if (!cpts || !cpts.length) { | 
						|
      return []; | 
						|
    } | 
						|
 | 
						|
    var result; | 
						|
 | 
						|
    if (index != null) { | 
						|
      if (!isArray(index)) { | 
						|
        index = [index]; | 
						|
      } | 
						|
 | 
						|
      result = filter(map(index, function (idx) { | 
						|
        return cpts[idx]; | 
						|
      }), function (val) { | 
						|
        return !!val; | 
						|
      }); | 
						|
    } else if (id != null) { | 
						|
      var isIdArray = isArray(id); | 
						|
      result = filter(cpts, function (cpt) { | 
						|
        return isIdArray && indexOf(id, cpt.id) >= 0 || !isIdArray && cpt.id === id; | 
						|
      }); | 
						|
    } else if (name != null) { | 
						|
      var isNameArray = isArray(name); | 
						|
      result = filter(cpts, function (cpt) { | 
						|
        return isNameArray && indexOf(name, cpt.name) >= 0 || !isNameArray && cpt.name === name; | 
						|
      }); | 
						|
    } else { | 
						|
      // Return all components with mainType | 
						|
      result = cpts.slice(); | 
						|
    } | 
						|
 | 
						|
    return filterBySubType(result, condition); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * The interface is different from queryComponents, | 
						|
   * which is convenient for inner usage. | 
						|
   * | 
						|
   * @usage | 
						|
   * var result = findComponents( | 
						|
   *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}} | 
						|
   * ); | 
						|
   * var result = findComponents( | 
						|
   *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}} | 
						|
   * ); | 
						|
   * var result = findComponents( | 
						|
   *     {mainType: 'series'}, | 
						|
   *     function (model, index) {...} | 
						|
   * ); | 
						|
   * // result like [component0, componnet1, ...] | 
						|
   * | 
						|
   * @param {Object} condition | 
						|
   * @param {string} condition.mainType Mandatory. | 
						|
   * @param {string} [condition.subType] Optional. | 
						|
   * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName}, | 
						|
   *        where xxx is mainType. | 
						|
   *        If query attribute is null/undefined or has no index/id/name, | 
						|
   *        do not filtering by query conditions, which is convenient for | 
						|
   *        no-payload situations or when target of action is global. | 
						|
   * @param {Function} [condition.filter] parameter: component, return boolean. | 
						|
   * @return {Array.<module:echarts/model/Component>} | 
						|
   */ | 
						|
  findComponents: function (condition) { | 
						|
    var query = condition.query; | 
						|
    var mainType = condition.mainType; | 
						|
    var queryCond = getQueryCond(query); | 
						|
    var result = queryCond ? this.queryComponents(queryCond) : this._componentsMap.get(mainType); | 
						|
    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; | 
						|
    } | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @usage | 
						|
   * eachComponent('legend', function (legendModel, index) { | 
						|
   *     ... | 
						|
   * }); | 
						|
   * eachComponent(function (componentType, model, index) { | 
						|
   *     // componentType does not include subType | 
						|
   *     // (componentType is 'xxx' but not 'xxx.aa') | 
						|
   * }); | 
						|
   * eachComponent( | 
						|
   *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}, | 
						|
   *     function (model, index) {...} | 
						|
   * ); | 
						|
   * eachComponent( | 
						|
   *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}, | 
						|
   *     function (model, index) {...} | 
						|
   * ); | 
						|
   * | 
						|
   * @param {string|Object=} mainType When mainType is object, the definition | 
						|
   *                                  is the same as the method 'findComponents'. | 
						|
   * @param {Function} cb | 
						|
   * @param {*} context | 
						|
   */ | 
						|
  eachComponent: function (mainType, cb, context) { | 
						|
    var componentsMap = this._componentsMap; | 
						|
 | 
						|
    if (typeof mainType === 'function') { | 
						|
      context = cb; | 
						|
      cb = mainType; | 
						|
      componentsMap.each(function (components, componentType) { | 
						|
        each(components, function (component, index) { | 
						|
          cb.call(context, componentType, component, index); | 
						|
        }); | 
						|
      }); | 
						|
    } else if (isString(mainType)) { | 
						|
      each(componentsMap.get(mainType), cb, context); | 
						|
    } else if (isObject(mainType)) { | 
						|
      var queryResult = this.findComponents(mainType); | 
						|
      each(queryResult, cb, context); | 
						|
    } | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @param {string} name | 
						|
   * @return {Array.<module:echarts/model/Series>} | 
						|
   */ | 
						|
  getSeriesByName: function (name) { | 
						|
    var series = this._componentsMap.get('series'); | 
						|
 | 
						|
    return filter(series, function (oneSeries) { | 
						|
      return oneSeries.name === name; | 
						|
    }); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @param {number} seriesIndex | 
						|
   * @return {module:echarts/model/Series} | 
						|
   */ | 
						|
  getSeriesByIndex: function (seriesIndex) { | 
						|
    return this._componentsMap.get('series')[seriesIndex]; | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * Get series list before filtered by type. | 
						|
   * FIXME: rename to getRawSeriesByType? | 
						|
   * | 
						|
   * @param {string} subType | 
						|
   * @return {Array.<module:echarts/model/Series>} | 
						|
   */ | 
						|
  getSeriesByType: function (subType) { | 
						|
    var series = this._componentsMap.get('series'); | 
						|
 | 
						|
    return filter(series, function (oneSeries) { | 
						|
      return oneSeries.subType === subType; | 
						|
    }); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @return {Array.<module:echarts/model/Series>} | 
						|
   */ | 
						|
  getSeries: function () { | 
						|
    return this._componentsMap.get('series').slice(); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @return {number} | 
						|
   */ | 
						|
  getSeriesCount: function () { | 
						|
    return this._componentsMap.get('series').length; | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * After filtering, series may be different | 
						|
   * frome raw series. | 
						|
   * | 
						|
   * @param {Function} cb | 
						|
   * @param {*} context | 
						|
   */ | 
						|
  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 | 
						|
   */ | 
						|
  eachRawSeries: function (cb, context) { | 
						|
    each(this._componentsMap.get('series'), cb, context); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * After filtering, series may be different. | 
						|
   * frome raw series. | 
						|
   * | 
						|
   * @parma {string} subType | 
						|
   * @param {Function} cb | 
						|
   * @param {*} context | 
						|
   */ | 
						|
  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. | 
						|
   * | 
						|
   * @parma {string} subType | 
						|
   * @param {Function} cb | 
						|
   * @param {*} context | 
						|
   */ | 
						|
  eachRawSeriesByType: function (subType, cb, context) { | 
						|
    return each(this.getSeriesByType(subType), cb, context); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @param {module:echarts/model/Series} seriesModel | 
						|
   */ | 
						|
  isSeriesFiltered: function (seriesModel) { | 
						|
    assertSeriesInitialized(this); | 
						|
    return this._seriesIndicesMap.get(seriesModel.componentIndex) == null; | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @return {Array.<number>} | 
						|
   */ | 
						|
  getCurrentSeriesIndices: function () { | 
						|
    return (this._seriesIndices || []).slice(); | 
						|
  }, | 
						|
 | 
						|
  /** | 
						|
   * @param {Function} cb | 
						|
   * @param {*} context | 
						|
   */ | 
						|
  filterSeries: function (cb, context) { | 
						|
    assertSeriesInitialized(this); | 
						|
    var filteredSeries = filter(this._componentsMap.get('series'), cb, context); | 
						|
    createSeriesIndices(this, filteredSeries); | 
						|
  }, | 
						|
  restoreData: function (payload) { | 
						|
    var componentsMap = this._componentsMap; | 
						|
    createSeriesIndices(this, componentsMap.get('series')); | 
						|
    var componentTypes = []; | 
						|
    componentsMap.each(function (components, componentType) { | 
						|
      componentTypes.push(componentType); | 
						|
    }); | 
						|
    ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType, dependencies) { | 
						|
      each(componentsMap.get(componentType), function (component) { | 
						|
        (componentType !== 'series' || !isNotTargetSeries(component, payload)) && component.restoreData(); | 
						|
      }); | 
						|
    }); | 
						|
  } | 
						|
}); | 
						|
 | 
						|
function isNotTargetSeries(seriesModel, payload) { | 
						|
  if (payload) { | 
						|
    var index = payload.seiresIndex; | 
						|
    var id = payload.seriesId; | 
						|
    var name = payload.seriesName; | 
						|
    return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name != null && seriesModel.name !== name; | 
						|
  } | 
						|
} | 
						|
/** | 
						|
 * @inner | 
						|
 */ | 
						|
 | 
						|
 | 
						|
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; | 
						|
    } // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理 | 
						|
 | 
						|
 | 
						|
    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 initBase(baseOption) { | 
						|
  baseOption = baseOption; // Using OPTION_INNER_KEY to mark that this option can not be used outside, | 
						|
  // i.e. `chart.setOption(chart.getModel().option);` is forbiden. | 
						|
 | 
						|
  this.option = {}; | 
						|
  this.option[OPTION_INNER_KEY] = 1; | 
						|
  /** | 
						|
   * Init with series: [], in case of calling findSeries method | 
						|
   * before series initialized. | 
						|
   * @type {Object.<string, Array.<module:echarts/model/Model>>} | 
						|
   * @private | 
						|
   */ | 
						|
 | 
						|
  this._componentsMap = createHashMap({ | 
						|
    series: [] | 
						|
  }); | 
						|
  /** | 
						|
   * Mapping between filtered series list and raw series list. | 
						|
   * key: filtered series indices, value: raw series indices. | 
						|
   * @type {Array.<nubmer>} | 
						|
   * @private | 
						|
   */ | 
						|
 | 
						|
  this._seriesIndices; | 
						|
  this._seriesIndicesMap; | 
						|
  mergeTheme(baseOption, this._theme.option); // TODO Needs clone when merging to the unexisted property | 
						|
 | 
						|
  merge(baseOption, globalDefault, false); | 
						|
  this.mergeOption(baseOption); | 
						|
} | 
						|
/** | 
						|
 * @inner | 
						|
 * @param {Array.<string>|string} types model types | 
						|
 * @return {Object} key: {string} type, value: {Array.<Object>} models | 
						|
 */ | 
						|
 | 
						|
 | 
						|
function getComponentsByTypes(componentsMap, types) { | 
						|
  if (!isArray(types)) { | 
						|
    types = types ? [types] : []; | 
						|
  } | 
						|
 | 
						|
  var ret = {}; | 
						|
  each(types, function (type) { | 
						|
    ret[type] = (componentsMap.get(type) || []).slice(); | 
						|
  }); | 
						|
  return ret; | 
						|
} | 
						|
/** | 
						|
 * @inner | 
						|
 */ | 
						|
 | 
						|
 | 
						|
function determineSubType(mainType, newCptOption, existComponent) { | 
						|
  var subType = newCptOption.type ? newCptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent. | 
						|
  : ComponentModel.determineSubType(mainType, newCptOption); // tooltip, markline, markpoint may always has no subType | 
						|
 | 
						|
  return subType; | 
						|
} | 
						|
/** | 
						|
 * @inner | 
						|
 */ | 
						|
 | 
						|
 | 
						|
function createSeriesIndices(ecModel, seriesModels) { | 
						|
  ecModel._seriesIndicesMap = createHashMap(ecModel._seriesIndices = map(seriesModels, function (series) { | 
						|
    return series.componentIndex; | 
						|
  }) || []); | 
						|
} | 
						|
/** | 
						|
 * @inner | 
						|
 */ | 
						|
 | 
						|
 | 
						|
function filterBySubType(components, condition) { | 
						|
  // Using hasOwnProperty for restrict. Consider | 
						|
  // subType is undefined in user payload. | 
						|
  return condition.hasOwnProperty('subType') ? filter(components, function (cpt) { | 
						|
    return cpt.subType === condition.subType; | 
						|
  }) : components; | 
						|
} | 
						|
/** | 
						|
 * @inner | 
						|
 */ | 
						|
 | 
						|
 | 
						|
function assertSeriesInitialized(ecModel) {} | 
						|
 | 
						|
mixin(GlobalModel, colorPaletteMixin); | 
						|
var _default = GlobalModel; | 
						|
module.exports = _default; |