Global.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var _config = require("../config");
  20. var __DEV__ = _config.__DEV__;
  21. var _util = require("zrender/lib/core/util");
  22. var each = _util.each;
  23. var filter = _util.filter;
  24. var map = _util.map;
  25. var isArray = _util.isArray;
  26. var indexOf = _util.indexOf;
  27. var isObject = _util.isObject;
  28. var isString = _util.isString;
  29. var createHashMap = _util.createHashMap;
  30. var assert = _util.assert;
  31. var clone = _util.clone;
  32. var merge = _util.merge;
  33. var extend = _util.extend;
  34. var mixin = _util.mixin;
  35. var modelUtil = require("../util/model");
  36. var Model = require("./Model");
  37. var ComponentModel = require("./Component");
  38. var globalDefault = require("./globalDefault");
  39. var colorPaletteMixin = require("./mixin/colorPalette");
  40. var _sourceHelper = require("../data/helper/sourceHelper");
  41. var resetSourceDefaulter = _sourceHelper.resetSourceDefaulter;
  42. /*
  43. * Licensed to the Apache Software Foundation (ASF) under one
  44. * or more contributor license agreements. See the NOTICE file
  45. * distributed with this work for additional information
  46. * regarding copyright ownership. The ASF licenses this file
  47. * to you under the Apache License, Version 2.0 (the
  48. * "License"); you may not use this file except in compliance
  49. * with the License. You may obtain a copy of the License at
  50. *
  51. * http://www.apache.org/licenses/LICENSE-2.0
  52. *
  53. * Unless required by applicable law or agreed to in writing,
  54. * software distributed under the License is distributed on an
  55. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  56. * KIND, either express or implied. See the License for the
  57. * specific language governing permissions and limitations
  58. * under the License.
  59. */
  60. /**
  61. * ECharts global model
  62. *
  63. * @module {echarts/model/Global}
  64. */
  65. /**
  66. * Caution: If the mechanism should be changed some day, these cases
  67. * should be considered:
  68. *
  69. * (1) In `merge option` mode, if using the same option to call `setOption`
  70. * many times, the result should be the same (try our best to ensure that).
  71. * (2) In `merge option` mode, if a component has no id/name specified, it
  72. * will be merged by index, and the result sequence of the components is
  73. * consistent to the original sequence.
  74. * (3) `reset` feature (in toolbox). Find detailed info in comments about
  75. * `mergeOption` in module:echarts/model/OptionManager.
  76. */
  77. var OPTION_INNER_KEY = '\0_ec_inner';
  78. /**
  79. * @alias module:echarts/model/Global
  80. *
  81. * @param {Object} option
  82. * @param {module:echarts/model/Model} parentModel
  83. * @param {Object} theme
  84. */
  85. var GlobalModel = Model.extend({
  86. init: function (option, parentModel, theme, optionManager) {
  87. theme = theme || {};
  88. this.option = null; // Mark as not initialized.
  89. /**
  90. * @type {module:echarts/model/Model}
  91. * @private
  92. */
  93. this._theme = new Model(theme);
  94. /**
  95. * @type {module:echarts/model/OptionManager}
  96. */
  97. this._optionManager = optionManager;
  98. },
  99. setOption: function (option, optionPreprocessorFuncs) {
  100. assert(!(OPTION_INNER_KEY in option), 'please use chart.getOption()');
  101. this._optionManager.setOption(option, optionPreprocessorFuncs);
  102. this.resetOption(null);
  103. },
  104. /**
  105. * @param {string} type null/undefined: reset all.
  106. * 'recreate': force recreate all.
  107. * 'timeline': only reset timeline option
  108. * 'media': only reset media query option
  109. * @return {boolean} Whether option changed.
  110. */
  111. resetOption: function (type) {
  112. var optionChanged = false;
  113. var optionManager = this._optionManager;
  114. if (!type || type === 'recreate') {
  115. var baseOption = optionManager.mountOption(type === 'recreate');
  116. if (!this.option || type === 'recreate') {
  117. initBase.call(this, baseOption);
  118. } else {
  119. this.restoreData();
  120. this.mergeOption(baseOption);
  121. }
  122. optionChanged = true;
  123. }
  124. if (type === 'timeline' || type === 'media') {
  125. this.restoreData();
  126. }
  127. if (!type || type === 'recreate' || type === 'timeline') {
  128. var timelineOption = optionManager.getTimelineOption(this);
  129. timelineOption && (this.mergeOption(timelineOption), optionChanged = true);
  130. }
  131. if (!type || type === 'recreate' || type === 'media') {
  132. var mediaOptions = optionManager.getMediaOption(this, this._api);
  133. if (mediaOptions.length) {
  134. each(mediaOptions, function (mediaOption) {
  135. this.mergeOption(mediaOption, optionChanged = true);
  136. }, this);
  137. }
  138. }
  139. return optionChanged;
  140. },
  141. /**
  142. * @protected
  143. */
  144. mergeOption: function (newOption) {
  145. var option = this.option;
  146. var componentsMap = this._componentsMap;
  147. var newCptTypes = [];
  148. resetSourceDefaulter(this); // If no component class, merge directly.
  149. // For example: color, animaiton options, etc.
  150. each(newOption, function (componentOption, mainType) {
  151. if (componentOption == null) {
  152. return;
  153. }
  154. if (!ComponentModel.hasClass(mainType)) {
  155. // globalSettingTask.dirty();
  156. option[mainType] = option[mainType] == null ? clone(componentOption) : merge(option[mainType], componentOption, true);
  157. } else if (mainType) {
  158. newCptTypes.push(mainType);
  159. }
  160. });
  161. ComponentModel.topologicalTravel(newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this);
  162. function visitComponent(mainType, dependencies) {
  163. var newCptOptionList = modelUtil.normalizeToArray(newOption[mainType]);
  164. var mapResult = modelUtil.mappingToExists(componentsMap.get(mainType), newCptOptionList);
  165. modelUtil.makeIdAndName(mapResult); // Set mainType and complete subType.
  166. each(mapResult, function (item, index) {
  167. var opt = item.option;
  168. if (isObject(opt)) {
  169. item.keyInfo.mainType = mainType;
  170. item.keyInfo.subType = determineSubType(mainType, opt, item.exist);
  171. }
  172. });
  173. var dependentModels = getComponentsByTypes(componentsMap, dependencies);
  174. option[mainType] = [];
  175. componentsMap.set(mainType, []);
  176. each(mapResult, function (resultItem, index) {
  177. var componentModel = resultItem.exist;
  178. var newCptOption = resultItem.option;
  179. assert(isObject(newCptOption) || componentModel, 'Empty component definition'); // Consider where is no new option and should be merged using {},
  180. // see removeEdgeAndAdd in topologicalTravel and
  181. // ComponentModel.getAllClassMainTypes.
  182. if (!newCptOption) {
  183. componentModel.mergeOption({}, this);
  184. componentModel.optionUpdated({}, false);
  185. } else {
  186. var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, true);
  187. if (componentModel && componentModel.constructor === ComponentModelClass) {
  188. componentModel.name = resultItem.keyInfo.name; // componentModel.settingTask && componentModel.settingTask.dirty();
  189. componentModel.mergeOption(newCptOption, this);
  190. componentModel.optionUpdated(newCptOption, false);
  191. } else {
  192. // PENDING Global as parent ?
  193. var extraOpt = extend({
  194. dependentModels: dependentModels,
  195. componentIndex: index
  196. }, resultItem.keyInfo);
  197. componentModel = new ComponentModelClass(newCptOption, this, this, extraOpt);
  198. extend(componentModel, extraOpt);
  199. componentModel.init(newCptOption, this, this, extraOpt); // Call optionUpdated after init.
  200. // newCptOption has been used as componentModel.option
  201. // and may be merged with theme and default, so pass null
  202. // to avoid confusion.
  203. componentModel.optionUpdated(null, true);
  204. }
  205. }
  206. componentsMap.get(mainType)[index] = componentModel;
  207. option[mainType][index] = componentModel.option;
  208. }, this); // Backup series for filtering.
  209. if (mainType === 'series') {
  210. createSeriesIndices(this, componentsMap.get('series'));
  211. }
  212. }
  213. this._seriesIndicesMap = createHashMap(this._seriesIndices = this._seriesIndices || []);
  214. },
  215. /**
  216. * Get option for output (cloned option and inner info removed)
  217. * @public
  218. * @return {Object}
  219. */
  220. getOption: function () {
  221. var option = clone(this.option);
  222. each(option, function (opts, mainType) {
  223. if (ComponentModel.hasClass(mainType)) {
  224. var opts = modelUtil.normalizeToArray(opts);
  225. for (var i = opts.length - 1; i >= 0; i--) {
  226. // Remove options with inner id.
  227. if (modelUtil.isIdInner(opts[i])) {
  228. opts.splice(i, 1);
  229. }
  230. }
  231. option[mainType] = opts;
  232. }
  233. });
  234. delete option[OPTION_INNER_KEY];
  235. return option;
  236. },
  237. /**
  238. * @return {module:echarts/model/Model}
  239. */
  240. getTheme: function () {
  241. return this._theme;
  242. },
  243. /**
  244. * @param {string} mainType
  245. * @param {number} [idx=0]
  246. * @return {module:echarts/model/Component}
  247. */
  248. getComponent: function (mainType, idx) {
  249. var list = this._componentsMap.get(mainType);
  250. if (list) {
  251. return list[idx || 0];
  252. }
  253. },
  254. /**
  255. * If none of index and id and name used, return all components with mainType.
  256. * @param {Object} condition
  257. * @param {string} condition.mainType
  258. * @param {string} [condition.subType] If ignore, only query by mainType
  259. * @param {number|Array.<number>} [condition.index] Either input index or id or name.
  260. * @param {string|Array.<string>} [condition.id] Either input index or id or name.
  261. * @param {string|Array.<string>} [condition.name] Either input index or id or name.
  262. * @return {Array.<module:echarts/model/Component>}
  263. */
  264. queryComponents: function (condition) {
  265. var mainType = condition.mainType;
  266. if (!mainType) {
  267. return [];
  268. }
  269. var index = condition.index;
  270. var id = condition.id;
  271. var name = condition.name;
  272. var cpts = this._componentsMap.get(mainType);
  273. if (!cpts || !cpts.length) {
  274. return [];
  275. }
  276. var result;
  277. if (index != null) {
  278. if (!isArray(index)) {
  279. index = [index];
  280. }
  281. result = filter(map(index, function (idx) {
  282. return cpts[idx];
  283. }), function (val) {
  284. return !!val;
  285. });
  286. } else if (id != null) {
  287. var isIdArray = isArray(id);
  288. result = filter(cpts, function (cpt) {
  289. return isIdArray && indexOf(id, cpt.id) >= 0 || !isIdArray && cpt.id === id;
  290. });
  291. } else if (name != null) {
  292. var isNameArray = isArray(name);
  293. result = filter(cpts, function (cpt) {
  294. return isNameArray && indexOf(name, cpt.name) >= 0 || !isNameArray && cpt.name === name;
  295. });
  296. } else {
  297. // Return all components with mainType
  298. result = cpts.slice();
  299. }
  300. return filterBySubType(result, condition);
  301. },
  302. /**
  303. * The interface is different from queryComponents,
  304. * which is convenient for inner usage.
  305. *
  306. * @usage
  307. * var result = findComponents(
  308. * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}
  309. * );
  310. * var result = findComponents(
  311. * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}
  312. * );
  313. * var result = findComponents(
  314. * {mainType: 'series',
  315. * filter: function (model, index) {...}}
  316. * );
  317. * // result like [component0, componnet1, ...]
  318. *
  319. * @param {Object} condition
  320. * @param {string} condition.mainType Mandatory.
  321. * @param {string} [condition.subType] Optional.
  322. * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},
  323. * where xxx is mainType.
  324. * If query attribute is null/undefined or has no index/id/name,
  325. * do not filtering by query conditions, which is convenient for
  326. * no-payload situations or when target of action is global.
  327. * @param {Function} [condition.filter] parameter: component, return boolean.
  328. * @return {Array.<module:echarts/model/Component>}
  329. */
  330. findComponents: function (condition) {
  331. var query = condition.query;
  332. var mainType = condition.mainType;
  333. var queryCond = getQueryCond(query);
  334. var result = queryCond ? this.queryComponents(queryCond) : this._componentsMap.get(mainType);
  335. return doFilter(filterBySubType(result, condition));
  336. function getQueryCond(q) {
  337. var indexAttr = mainType + 'Index';
  338. var idAttr = mainType + 'Id';
  339. var nameAttr = mainType + 'Name';
  340. return q && (q[indexAttr] != null || q[idAttr] != null || q[nameAttr] != null) ? {
  341. mainType: mainType,
  342. // subType will be filtered finally.
  343. index: q[indexAttr],
  344. id: q[idAttr],
  345. name: q[nameAttr]
  346. } : null;
  347. }
  348. function doFilter(res) {
  349. return condition.filter ? filter(res, condition.filter) : res;
  350. }
  351. },
  352. /**
  353. * @usage
  354. * eachComponent('legend', function (legendModel, index) {
  355. * ...
  356. * });
  357. * eachComponent(function (componentType, model, index) {
  358. * // componentType does not include subType
  359. * // (componentType is 'xxx' but not 'xxx.aa')
  360. * });
  361. * eachComponent(
  362. * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},
  363. * function (model, index) {...}
  364. * );
  365. * eachComponent(
  366. * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},
  367. * function (model, index) {...}
  368. * );
  369. *
  370. * @param {string|Object=} mainType When mainType is object, the definition
  371. * is the same as the method 'findComponents'.
  372. * @param {Function} cb
  373. * @param {*} context
  374. */
  375. eachComponent: function (mainType, cb, context) {
  376. var componentsMap = this._componentsMap;
  377. if (typeof mainType === 'function') {
  378. context = cb;
  379. cb = mainType;
  380. componentsMap.each(function (components, componentType) {
  381. each(components, function (component, index) {
  382. cb.call(context, componentType, component, index);
  383. });
  384. });
  385. } else if (isString(mainType)) {
  386. each(componentsMap.get(mainType), cb, context);
  387. } else if (isObject(mainType)) {
  388. var queryResult = this.findComponents(mainType);
  389. each(queryResult, cb, context);
  390. }
  391. },
  392. /**
  393. * @param {string} name
  394. * @return {Array.<module:echarts/model/Series>}
  395. */
  396. getSeriesByName: function (name) {
  397. var series = this._componentsMap.get('series');
  398. return filter(series, function (oneSeries) {
  399. return oneSeries.name === name;
  400. });
  401. },
  402. /**
  403. * @param {number} seriesIndex
  404. * @return {module:echarts/model/Series}
  405. */
  406. getSeriesByIndex: function (seriesIndex) {
  407. return this._componentsMap.get('series')[seriesIndex];
  408. },
  409. /**
  410. * Get series list before filtered by type.
  411. * FIXME: rename to getRawSeriesByType?
  412. *
  413. * @param {string} subType
  414. * @return {Array.<module:echarts/model/Series>}
  415. */
  416. getSeriesByType: function (subType) {
  417. var series = this._componentsMap.get('series');
  418. return filter(series, function (oneSeries) {
  419. return oneSeries.subType === subType;
  420. });
  421. },
  422. /**
  423. * @return {Array.<module:echarts/model/Series>}
  424. */
  425. getSeries: function () {
  426. return this._componentsMap.get('series').slice();
  427. },
  428. /**
  429. * @return {number}
  430. */
  431. getSeriesCount: function () {
  432. return this._componentsMap.get('series').length;
  433. },
  434. /**
  435. * After filtering, series may be different
  436. * frome raw series.
  437. *
  438. * @param {Function} cb
  439. * @param {*} context
  440. */
  441. eachSeries: function (cb, context) {
  442. assertSeriesInitialized(this);
  443. each(this._seriesIndices, function (rawSeriesIndex) {
  444. var series = this._componentsMap.get('series')[rawSeriesIndex];
  445. cb.call(context, series, rawSeriesIndex);
  446. }, this);
  447. },
  448. /**
  449. * Iterate raw series before filtered.
  450. *
  451. * @param {Function} cb
  452. * @param {*} context
  453. */
  454. eachRawSeries: function (cb, context) {
  455. each(this._componentsMap.get('series'), cb, context);
  456. },
  457. /**
  458. * After filtering, series may be different.
  459. * frome raw series.
  460. *
  461. * @param {string} subType.
  462. * @param {Function} cb
  463. * @param {*} context
  464. */
  465. eachSeriesByType: function (subType, cb, context) {
  466. assertSeriesInitialized(this);
  467. each(this._seriesIndices, function (rawSeriesIndex) {
  468. var series = this._componentsMap.get('series')[rawSeriesIndex];
  469. if (series.subType === subType) {
  470. cb.call(context, series, rawSeriesIndex);
  471. }
  472. }, this);
  473. },
  474. /**
  475. * Iterate raw series before filtered of given type.
  476. *
  477. * @parma {string} subType
  478. * @param {Function} cb
  479. * @param {*} context
  480. */
  481. eachRawSeriesByType: function (subType, cb, context) {
  482. return each(this.getSeriesByType(subType), cb, context);
  483. },
  484. /**
  485. * @param {module:echarts/model/Series} seriesModel
  486. */
  487. isSeriesFiltered: function (seriesModel) {
  488. assertSeriesInitialized(this);
  489. return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;
  490. },
  491. /**
  492. * @return {Array.<number>}
  493. */
  494. getCurrentSeriesIndices: function () {
  495. return (this._seriesIndices || []).slice();
  496. },
  497. /**
  498. * @param {Function} cb
  499. * @param {*} context
  500. */
  501. filterSeries: function (cb, context) {
  502. assertSeriesInitialized(this);
  503. var filteredSeries = filter(this._componentsMap.get('series'), cb, context);
  504. createSeriesIndices(this, filteredSeries);
  505. },
  506. restoreData: function (payload) {
  507. var componentsMap = this._componentsMap;
  508. createSeriesIndices(this, componentsMap.get('series'));
  509. var componentTypes = [];
  510. componentsMap.each(function (components, componentType) {
  511. componentTypes.push(componentType);
  512. });
  513. ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType, dependencies) {
  514. each(componentsMap.get(componentType), function (component) {
  515. (componentType !== 'series' || !isNotTargetSeries(component, payload)) && component.restoreData();
  516. });
  517. });
  518. }
  519. });
  520. function isNotTargetSeries(seriesModel, payload) {
  521. if (payload) {
  522. var index = payload.seiresIndex;
  523. var id = payload.seriesId;
  524. var name = payload.seriesName;
  525. return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name != null && seriesModel.name !== name;
  526. }
  527. }
  528. /**
  529. * @inner
  530. */
  531. function mergeTheme(option, theme) {
  532. // PENDING
  533. // NOT use `colorLayer` in theme if option has `color`
  534. var notMergeColorLayer = option.color && !option.colorLayer;
  535. each(theme, function (themeItem, name) {
  536. if (name === 'colorLayer' && notMergeColorLayer) {
  537. return;
  538. } // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理
  539. if (!ComponentModel.hasClass(name)) {
  540. if (typeof themeItem === 'object') {
  541. option[name] = !option[name] ? clone(themeItem) : merge(option[name], themeItem, false);
  542. } else {
  543. if (option[name] == null) {
  544. option[name] = themeItem;
  545. }
  546. }
  547. }
  548. });
  549. }
  550. function initBase(baseOption) {
  551. baseOption = baseOption; // Using OPTION_INNER_KEY to mark that this option can not be used outside,
  552. // i.e. `chart.setOption(chart.getModel().option);` is forbiden.
  553. this.option = {};
  554. this.option[OPTION_INNER_KEY] = 1;
  555. /**
  556. * Init with series: [], in case of calling findSeries method
  557. * before series initialized.
  558. * @type {Object.<string, Array.<module:echarts/model/Model>>}
  559. * @private
  560. */
  561. this._componentsMap = createHashMap({
  562. series: []
  563. });
  564. /**
  565. * Mapping between filtered series list and raw series list.
  566. * key: filtered series indices, value: raw series indices.
  567. * @type {Array.<nubmer>}
  568. * @private
  569. */
  570. this._seriesIndices;
  571. this._seriesIndicesMap;
  572. mergeTheme(baseOption, this._theme.option); // TODO Needs clone when merging to the unexisted property
  573. merge(baseOption, globalDefault, false);
  574. this.mergeOption(baseOption);
  575. }
  576. /**
  577. * @inner
  578. * @param {Array.<string>|string} types model types
  579. * @return {Object} key: {string} type, value: {Array.<Object>} models
  580. */
  581. function getComponentsByTypes(componentsMap, types) {
  582. if (!isArray(types)) {
  583. types = types ? [types] : [];
  584. }
  585. var ret = {};
  586. each(types, function (type) {
  587. ret[type] = (componentsMap.get(type) || []).slice();
  588. });
  589. return ret;
  590. }
  591. /**
  592. * @inner
  593. */
  594. function determineSubType(mainType, newCptOption, existComponent) {
  595. var subType = newCptOption.type ? newCptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent.
  596. : ComponentModel.determineSubType(mainType, newCptOption); // tooltip, markline, markpoint may always has no subType
  597. return subType;
  598. }
  599. /**
  600. * @inner
  601. */
  602. function createSeriesIndices(ecModel, seriesModels) {
  603. ecModel._seriesIndicesMap = createHashMap(ecModel._seriesIndices = map(seriesModels, function (series) {
  604. return series.componentIndex;
  605. }) || []);
  606. }
  607. /**
  608. * @inner
  609. */
  610. function filterBySubType(components, condition) {
  611. // Using hasOwnProperty for restrict. Consider
  612. // subType is undefined in user payload.
  613. return condition.hasOwnProperty('subType') ? filter(components, function (cpt) {
  614. return cpt.subType === condition.subType;
  615. }) : components;
  616. }
  617. /**
  618. * @inner
  619. */
  620. function assertSeriesInitialized(ecModel) {}
  621. mixin(GlobalModel, colorPaletteMixin);
  622. var _default = GlobalModel;
  623. module.exports = _default;