SeriesData.js 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  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. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. /* global Int32Array */
  41. import * as zrUtil from 'zrender/lib/core/util.js';
  42. import Model from '../model/Model.js';
  43. import DataDiffer from './DataDiffer.js';
  44. import { DefaultDataProvider } from './helper/dataProvider.js';
  45. import { summarizeDimensions } from './helper/dimensionHelper.js';
  46. import SeriesDimensionDefine from './SeriesDimensionDefine.js';
  47. import { SOURCE_FORMAT_TYPED_ARRAY, SOURCE_FORMAT_ORIGINAL } from '../util/types.js';
  48. import { convertOptionIdName, isDataItemOption } from '../util/model.js';
  49. import { setCommonECData } from '../util/innerStore.js';
  50. import { isSourceInstance } from './Source.js';
  51. import DataStore from './DataStore.js';
  52. import { isSeriesDataSchema } from './helper/SeriesDataSchema.js';
  53. var isObject = zrUtil.isObject;
  54. var map = zrUtil.map;
  55. var CtorInt32Array = typeof Int32Array === 'undefined' ? Array : Int32Array; // Use prefix to avoid index to be the same as otherIdList[idx],
  56. // which will cause weird update animation.
  57. var ID_PREFIX = 'e\0\0';
  58. var INDEX_NOT_FOUND = -1; // type SeriesDimensionIndex = DimensionIndex;
  59. var TRANSFERABLE_PROPERTIES = ['hasItemOption', '_nameList', '_idList', '_invertedIndicesMap', '_dimSummary', 'userOutput', '_rawData', '_dimValueGetter', '_nameDimIdx', '_idDimIdx', '_nameRepeatCount'];
  60. var CLONE_PROPERTIES = ['_approximateExtent']; // -----------------------------
  61. // Internal method declarations:
  62. // -----------------------------
  63. var prepareInvertedIndex;
  64. var getId;
  65. var getIdNameFromStore;
  66. var normalizeDimensions;
  67. var transferProperties;
  68. var cloneListForMapAndSample;
  69. var makeIdFromName;
  70. var SeriesData =
  71. /** @class */
  72. function () {
  73. /**
  74. * @param dimensionsInput.dimensions
  75. * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].
  76. * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius
  77. */
  78. function SeriesData(dimensionsInput, hostModel) {
  79. this.type = 'list';
  80. this._dimOmitted = false;
  81. this._nameList = [];
  82. this._idList = []; // Models of data option is stored sparse for optimizing memory cost
  83. // Never used yet (not used yet).
  84. // private _optionModels: Model[] = [];
  85. // Global visual properties after visual coding
  86. this._visual = {}; // Global layout properties.
  87. this._layout = {}; // Item visual properties after visual coding
  88. this._itemVisuals = []; // Item layout properties after layout
  89. this._itemLayouts = []; // Graphic elements
  90. this._graphicEls = []; // key: dim, value: extent
  91. this._approximateExtent = {};
  92. this._calculationInfo = {}; // Having detected that there is data item is non primitive type
  93. // (in type `OptionDataItemObject`).
  94. // Like `data: [ { value: xx, itemStyle: {...} }, ...]`
  95. // At present it only happen in `SOURCE_FORMAT_ORIGINAL`.
  96. this.hasItemOption = false; // Methods that create a new list based on this list should be listed here.
  97. // Notice that those method should `RETURN` the new list.
  98. this.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'lttbDownSample', 'map']; // Methods that change indices of this list should be listed here.
  99. this.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];
  100. this.DOWNSAMPLE_METHODS = ['downSample', 'lttbDownSample'];
  101. var dimensions;
  102. var assignStoreDimIdx = false;
  103. if (isSeriesDataSchema(dimensionsInput)) {
  104. dimensions = dimensionsInput.dimensions;
  105. this._dimOmitted = dimensionsInput.isDimensionOmitted();
  106. this._schema = dimensionsInput;
  107. } else {
  108. assignStoreDimIdx = true;
  109. dimensions = dimensionsInput;
  110. }
  111. dimensions = dimensions || ['x', 'y'];
  112. var dimensionInfos = {};
  113. var dimensionNames = [];
  114. var invertedIndicesMap = {};
  115. var needsHasOwn = false;
  116. var emptyObj = {};
  117. for (var i = 0; i < dimensions.length; i++) {
  118. // Use the original dimensions[i], where other flag props may exists.
  119. var dimInfoInput = dimensions[i];
  120. var dimensionInfo = zrUtil.isString(dimInfoInput) ? new SeriesDimensionDefine({
  121. name: dimInfoInput
  122. }) : !(dimInfoInput instanceof SeriesDimensionDefine) ? new SeriesDimensionDefine(dimInfoInput) : dimInfoInput;
  123. var dimensionName = dimensionInfo.name;
  124. dimensionInfo.type = dimensionInfo.type || 'float';
  125. if (!dimensionInfo.coordDim) {
  126. dimensionInfo.coordDim = dimensionName;
  127. dimensionInfo.coordDimIndex = 0;
  128. }
  129. var otherDims = dimensionInfo.otherDims = dimensionInfo.otherDims || {};
  130. dimensionNames.push(dimensionName);
  131. dimensionInfos[dimensionName] = dimensionInfo;
  132. if (emptyObj[dimensionName] != null) {
  133. needsHasOwn = true;
  134. }
  135. if (dimensionInfo.createInvertedIndices) {
  136. invertedIndicesMap[dimensionName] = [];
  137. }
  138. if (otherDims.itemName === 0) {
  139. this._nameDimIdx = i;
  140. }
  141. if (otherDims.itemId === 0) {
  142. this._idDimIdx = i;
  143. }
  144. if (process.env.NODE_ENV !== 'production') {
  145. zrUtil.assert(assignStoreDimIdx || dimensionInfo.storeDimIndex >= 0);
  146. }
  147. if (assignStoreDimIdx) {
  148. dimensionInfo.storeDimIndex = i;
  149. }
  150. }
  151. this.dimensions = dimensionNames;
  152. this._dimInfos = dimensionInfos;
  153. this._initGetDimensionInfo(needsHasOwn);
  154. this.hostModel = hostModel;
  155. this._invertedIndicesMap = invertedIndicesMap;
  156. if (this._dimOmitted) {
  157. var dimIdxToName_1 = this._dimIdxToName = zrUtil.createHashMap();
  158. zrUtil.each(dimensionNames, function (dimName) {
  159. dimIdxToName_1.set(dimensionInfos[dimName].storeDimIndex, dimName);
  160. });
  161. }
  162. }
  163. /**
  164. *
  165. * Get concrete dimension name by dimension name or dimension index.
  166. * If input a dimension name, do not validate whether the dimension name exits.
  167. *
  168. * @caution
  169. * @param dim Must make sure the dimension is `SeriesDimensionLoose`.
  170. * Because only those dimensions will have auto-generated dimension names if not
  171. * have a user-specified name, and other dimensions will get a return of null/undefined.
  172. *
  173. * @notice Because of this reason, should better use `getDimensionIndex` instead, for examples:
  174. * ```js
  175. * const val = data.getStore().get(data.getDimensionIndex(dim), dataIdx);
  176. * ```
  177. *
  178. * @return Concrete dim name.
  179. */
  180. SeriesData.prototype.getDimension = function (dim) {
  181. var dimIdx = this._recognizeDimIndex(dim);
  182. if (dimIdx == null) {
  183. return dim;
  184. }
  185. dimIdx = dim;
  186. if (!this._dimOmitted) {
  187. return this.dimensions[dimIdx];
  188. } // Retrieve from series dimension definition because it probably contains
  189. // generated dimension name (like 'x', 'y').
  190. var dimName = this._dimIdxToName.get(dimIdx);
  191. if (dimName != null) {
  192. return dimName;
  193. }
  194. var sourceDimDef = this._schema.getSourceDimension(dimIdx);
  195. if (sourceDimDef) {
  196. return sourceDimDef.name;
  197. }
  198. };
  199. /**
  200. * Get dimension index in data store. Return -1 if not found.
  201. * Can be used to index value from getRawValue.
  202. */
  203. SeriesData.prototype.getDimensionIndex = function (dim) {
  204. var dimIdx = this._recognizeDimIndex(dim);
  205. if (dimIdx != null) {
  206. return dimIdx;
  207. }
  208. if (dim == null) {
  209. return -1;
  210. }
  211. var dimInfo = this._getDimInfo(dim);
  212. return dimInfo ? dimInfo.storeDimIndex : this._dimOmitted ? this._schema.getSourceDimensionIndex(dim) : -1;
  213. };
  214. /**
  215. * The meanings of the input parameter `dim`:
  216. *
  217. * + If dim is a number (e.g., `1`), it means the index of the dimension.
  218. * For example, `getDimension(0)` will return 'x' or 'lng' or 'radius'.
  219. * + If dim is a number-like string (e.g., `"1"`):
  220. * + If there is the same concrete dim name defined in `series.dimensions` or `dataset.dimensions`,
  221. * it means that concrete name.
  222. * + If not, it will be converted to a number, which means the index of the dimension.
  223. * (why? because of the backward compatibility. We have been tolerating number-like string in
  224. * dimension setting, although now it seems that it is not a good idea.)
  225. * For example, `visualMap[i].dimension: "1"` is the same meaning as `visualMap[i].dimension: 1`,
  226. * if no dimension name is defined as `"1"`.
  227. * + If dim is a not-number-like string, it means the concrete dim name.
  228. * For example, it can be be default name `"x"`, `"y"`, `"z"`, `"lng"`, `"lat"`, `"angle"`, `"radius"`,
  229. * or customized in `dimensions` property of option like `"age"`.
  230. *
  231. * @return recognized `DimensionIndex`. Otherwise return null/undefined (means that dim is `DimensionName`).
  232. */
  233. SeriesData.prototype._recognizeDimIndex = function (dim) {
  234. if (zrUtil.isNumber(dim) // If being a number-like string but not being defined as a dimension name.
  235. || dim != null && !isNaN(dim) && !this._getDimInfo(dim) && (!this._dimOmitted || this._schema.getSourceDimensionIndex(dim) < 0)) {
  236. return +dim;
  237. }
  238. };
  239. SeriesData.prototype._getStoreDimIndex = function (dim) {
  240. var dimIdx = this.getDimensionIndex(dim);
  241. if (process.env.NODE_ENV !== 'production') {
  242. if (dimIdx == null) {
  243. throw new Error('Unknown dimension ' + dim);
  244. }
  245. }
  246. return dimIdx;
  247. };
  248. /**
  249. * Get type and calculation info of particular dimension
  250. * @param dim
  251. * Dimension can be concrete names like x, y, z, lng, lat, angle, radius
  252. * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'
  253. */
  254. SeriesData.prototype.getDimensionInfo = function (dim) {
  255. // Do not clone, because there may be categories in dimInfo.
  256. return this._getDimInfo(this.getDimension(dim));
  257. };
  258. SeriesData.prototype._initGetDimensionInfo = function (needsHasOwn) {
  259. var dimensionInfos = this._dimInfos;
  260. this._getDimInfo = needsHasOwn ? function (dimName) {
  261. return dimensionInfos.hasOwnProperty(dimName) ? dimensionInfos[dimName] : undefined;
  262. } : function (dimName) {
  263. return dimensionInfos[dimName];
  264. };
  265. };
  266. /**
  267. * concrete dimension name list on coord.
  268. */
  269. SeriesData.prototype.getDimensionsOnCoord = function () {
  270. return this._dimSummary.dataDimsOnCoord.slice();
  271. };
  272. SeriesData.prototype.mapDimension = function (coordDim, idx) {
  273. var dimensionsSummary = this._dimSummary;
  274. if (idx == null) {
  275. return dimensionsSummary.encodeFirstDimNotExtra[coordDim];
  276. }
  277. var dims = dimensionsSummary.encode[coordDim];
  278. return dims ? dims[idx] : null;
  279. };
  280. SeriesData.prototype.mapDimensionsAll = function (coordDim) {
  281. var dimensionsSummary = this._dimSummary;
  282. var dims = dimensionsSummary.encode[coordDim];
  283. return (dims || []).slice();
  284. };
  285. SeriesData.prototype.getStore = function () {
  286. return this._store;
  287. };
  288. /**
  289. * Initialize from data
  290. * @param data source or data or data store.
  291. * @param nameList The name of a datum is used on data diff and
  292. * default label/tooltip.
  293. * A name can be specified in encode.itemName,
  294. * or dataItem.name (only for series option data),
  295. * or provided in nameList from outside.
  296. */
  297. SeriesData.prototype.initData = function (data, nameList, dimValueGetter) {
  298. var _this = this;
  299. var store;
  300. if (data instanceof DataStore) {
  301. store = data;
  302. }
  303. if (!store) {
  304. var dimensions = this.dimensions;
  305. var provider = isSourceInstance(data) || zrUtil.isArrayLike(data) ? new DefaultDataProvider(data, dimensions.length) : data;
  306. store = new DataStore();
  307. var dimensionInfos = map(dimensions, function (dimName) {
  308. return {
  309. type: _this._dimInfos[dimName].type,
  310. property: dimName
  311. };
  312. });
  313. store.initData(provider, dimensionInfos, dimValueGetter);
  314. }
  315. this._store = store; // Reset
  316. this._nameList = (nameList || []).slice();
  317. this._idList = [];
  318. this._nameRepeatCount = {};
  319. this._doInit(0, store.count()); // Cache summary info for fast visit. See "dimensionHelper".
  320. // Needs to be initialized after store is prepared.
  321. this._dimSummary = summarizeDimensions(this, this._schema);
  322. this.userOutput = this._dimSummary.userOutput;
  323. };
  324. /**
  325. * Caution: Can be only called on raw data (before `this._indices` created).
  326. */
  327. SeriesData.prototype.appendData = function (data) {
  328. var range = this._store.appendData(data);
  329. this._doInit(range[0], range[1]);
  330. };
  331. /**
  332. * Caution: Can be only called on raw data (before `this._indices` created).
  333. * This method does not modify `rawData` (`dataProvider`), but only
  334. * add values to store.
  335. *
  336. * The final count will be increased by `Math.max(values.length, names.length)`.
  337. *
  338. * @param values That is the SourceType: 'arrayRows', like
  339. * [
  340. * [12, 33, 44],
  341. * [NaN, 43, 1],
  342. * ['-', 'asdf', 0]
  343. * ]
  344. * Each item is exactly corresponding to a dimension.
  345. */
  346. SeriesData.prototype.appendValues = function (values, names) {
  347. var _a = this._store.appendValues(values, names.length),
  348. start = _a.start,
  349. end = _a.end;
  350. var shouldMakeIdFromName = this._shouldMakeIdFromName();
  351. this._updateOrdinalMeta();
  352. if (names) {
  353. for (var idx = start; idx < end; idx++) {
  354. var sourceIdx = idx - start;
  355. this._nameList[idx] = names[sourceIdx];
  356. if (shouldMakeIdFromName) {
  357. makeIdFromName(this, idx);
  358. }
  359. }
  360. }
  361. };
  362. SeriesData.prototype._updateOrdinalMeta = function () {
  363. var store = this._store;
  364. var dimensions = this.dimensions;
  365. for (var i = 0; i < dimensions.length; i++) {
  366. var dimInfo = this._dimInfos[dimensions[i]];
  367. if (dimInfo.ordinalMeta) {
  368. store.collectOrdinalMeta(dimInfo.storeDimIndex, dimInfo.ordinalMeta);
  369. }
  370. }
  371. };
  372. SeriesData.prototype._shouldMakeIdFromName = function () {
  373. var provider = this._store.getProvider();
  374. return this._idDimIdx == null && provider.getSource().sourceFormat !== SOURCE_FORMAT_TYPED_ARRAY && !provider.fillStorage;
  375. };
  376. SeriesData.prototype._doInit = function (start, end) {
  377. if (start >= end) {
  378. return;
  379. }
  380. var store = this._store;
  381. var provider = store.getProvider();
  382. this._updateOrdinalMeta();
  383. var nameList = this._nameList;
  384. var idList = this._idList;
  385. var sourceFormat = provider.getSource().sourceFormat;
  386. var isFormatOriginal = sourceFormat === SOURCE_FORMAT_ORIGINAL; // Each data item is value
  387. // [1, 2]
  388. // 2
  389. // Bar chart, line chart which uses category axis
  390. // only gives the 'y' value. 'x' value is the indices of category
  391. // Use a tempValue to normalize the value to be a (x, y) value
  392. // If dataItem is {name: ...} or {id: ...}, it has highest priority.
  393. // This kind of ids and names are always stored `_nameList` and `_idList`.
  394. if (isFormatOriginal && !provider.pure) {
  395. var sharedDataItem = [];
  396. for (var idx = start; idx < end; idx++) {
  397. // NOTICE: Try not to write things into dataItem
  398. var dataItem = provider.getItem(idx, sharedDataItem);
  399. if (!this.hasItemOption && isDataItemOption(dataItem)) {
  400. this.hasItemOption = true;
  401. }
  402. if (dataItem) {
  403. var itemName = dataItem.name;
  404. if (nameList[idx] == null && itemName != null) {
  405. nameList[idx] = convertOptionIdName(itemName, null);
  406. }
  407. var itemId = dataItem.id;
  408. if (idList[idx] == null && itemId != null) {
  409. idList[idx] = convertOptionIdName(itemId, null);
  410. }
  411. }
  412. }
  413. }
  414. if (this._shouldMakeIdFromName()) {
  415. for (var idx = start; idx < end; idx++) {
  416. makeIdFromName(this, idx);
  417. }
  418. }
  419. prepareInvertedIndex(this);
  420. };
  421. /**
  422. * PENDING: In fact currently this function is only used to short-circuit
  423. * the calling of `scale.unionExtentFromData` when data have been filtered by modules
  424. * like "dataZoom". `scale.unionExtentFromData` is used to calculate data extent for series on
  425. * an axis, but if a "axis related data filter module" is used, the extent of the axis have
  426. * been fixed and no need to calling `scale.unionExtentFromData` actually.
  427. * But if we add "custom data filter" in future, which is not "axis related", this method may
  428. * be still needed.
  429. *
  430. * Optimize for the scenario that data is filtered by a given extent.
  431. * Consider that if data amount is more than hundreds of thousand,
  432. * extent calculation will cost more than 10ms and the cache will
  433. * be erased because of the filtering.
  434. */
  435. SeriesData.prototype.getApproximateExtent = function (dim) {
  436. return this._approximateExtent[dim] || this._store.getDataExtent(this._getStoreDimIndex(dim));
  437. };
  438. /**
  439. * Calculate extent on a filtered data might be time consuming.
  440. * Approximate extent is only used for: calculate extent of filtered data outside.
  441. */
  442. SeriesData.prototype.setApproximateExtent = function (extent, dim) {
  443. dim = this.getDimension(dim);
  444. this._approximateExtent[dim] = extent.slice();
  445. };
  446. SeriesData.prototype.getCalculationInfo = function (key) {
  447. return this._calculationInfo[key];
  448. };
  449. SeriesData.prototype.setCalculationInfo = function (key, value) {
  450. isObject(key) ? zrUtil.extend(this._calculationInfo, key) : this._calculationInfo[key] = value;
  451. };
  452. /**
  453. * @return Never be null/undefined. `number` will be converted to string. Because:
  454. * In most cases, name is used in display, where returning a string is more convenient.
  455. * In other cases, name is used in query (see `indexOfName`), where we can keep the
  456. * rule that name `2` equals to name `'2'`.
  457. */
  458. SeriesData.prototype.getName = function (idx) {
  459. var rawIndex = this.getRawIndex(idx);
  460. var name = this._nameList[rawIndex];
  461. if (name == null && this._nameDimIdx != null) {
  462. name = getIdNameFromStore(this, this._nameDimIdx, rawIndex);
  463. }
  464. if (name == null) {
  465. name = '';
  466. }
  467. return name;
  468. };
  469. SeriesData.prototype._getCategory = function (dimIdx, idx) {
  470. var ordinal = this._store.get(dimIdx, idx);
  471. var ordinalMeta = this._store.getOrdinalMeta(dimIdx);
  472. if (ordinalMeta) {
  473. return ordinalMeta.categories[ordinal];
  474. }
  475. return ordinal;
  476. };
  477. /**
  478. * @return Never null/undefined. `number` will be converted to string. Because:
  479. * In all cases having encountered at present, id is used in making diff comparison, which
  480. * are usually based on hash map. We can keep the rule that the internal id are always string
  481. * (treat `2` is the same as `'2'`) to make the related logic simple.
  482. */
  483. SeriesData.prototype.getId = function (idx) {
  484. return getId(this, this.getRawIndex(idx));
  485. };
  486. SeriesData.prototype.count = function () {
  487. return this._store.count();
  488. };
  489. /**
  490. * Get value. Return NaN if idx is out of range.
  491. *
  492. * @notice Should better to use `data.getStore().get(dimIndex, dataIdx)` instead.
  493. */
  494. SeriesData.prototype.get = function (dim, idx) {
  495. var store = this._store;
  496. var dimInfo = this._dimInfos[dim];
  497. if (dimInfo) {
  498. return store.get(dimInfo.storeDimIndex, idx);
  499. }
  500. };
  501. /**
  502. * @notice Should better to use `data.getStore().getByRawIndex(dimIndex, dataIdx)` instead.
  503. */
  504. SeriesData.prototype.getByRawIndex = function (dim, rawIdx) {
  505. var store = this._store;
  506. var dimInfo = this._dimInfos[dim];
  507. if (dimInfo) {
  508. return store.getByRawIndex(dimInfo.storeDimIndex, rawIdx);
  509. }
  510. };
  511. SeriesData.prototype.getIndices = function () {
  512. return this._store.getIndices();
  513. };
  514. SeriesData.prototype.getDataExtent = function (dim) {
  515. return this._store.getDataExtent(this._getStoreDimIndex(dim));
  516. };
  517. SeriesData.prototype.getSum = function (dim) {
  518. return this._store.getSum(this._getStoreDimIndex(dim));
  519. };
  520. SeriesData.prototype.getMedian = function (dim) {
  521. return this._store.getMedian(this._getStoreDimIndex(dim));
  522. };
  523. SeriesData.prototype.getValues = function (dimensions, idx) {
  524. var _this = this;
  525. var store = this._store;
  526. return zrUtil.isArray(dimensions) ? store.getValues(map(dimensions, function (dim) {
  527. return _this._getStoreDimIndex(dim);
  528. }), idx) : store.getValues(dimensions);
  529. };
  530. /**
  531. * If value is NaN. Including '-'
  532. * Only check the coord dimensions.
  533. */
  534. SeriesData.prototype.hasValue = function (idx) {
  535. var dataDimIndicesOnCoord = this._dimSummary.dataDimIndicesOnCoord;
  536. for (var i = 0, len = dataDimIndicesOnCoord.length; i < len; i++) {
  537. // Ordinal type originally can be string or number.
  538. // But when an ordinal type is used on coord, it can
  539. // not be string but only number. So we can also use isNaN.
  540. if (isNaN(this._store.get(dataDimIndicesOnCoord[i], idx))) {
  541. return false;
  542. }
  543. }
  544. return true;
  545. };
  546. /**
  547. * Retrieve the index with given name
  548. */
  549. SeriesData.prototype.indexOfName = function (name) {
  550. for (var i = 0, len = this._store.count(); i < len; i++) {
  551. if (this.getName(i) === name) {
  552. return i;
  553. }
  554. }
  555. return -1;
  556. };
  557. SeriesData.prototype.getRawIndex = function (idx) {
  558. return this._store.getRawIndex(idx);
  559. };
  560. SeriesData.prototype.indexOfRawIndex = function (rawIndex) {
  561. return this._store.indexOfRawIndex(rawIndex);
  562. };
  563. /**
  564. * Only support the dimension which inverted index created.
  565. * Do not support other cases until required.
  566. * @param dim concrete dim
  567. * @param value ordinal index
  568. * @return rawIndex
  569. */
  570. SeriesData.prototype.rawIndexOf = function (dim, value) {
  571. var invertedIndices = dim && this._invertedIndicesMap[dim];
  572. if (process.env.NODE_ENV !== 'production') {
  573. if (!invertedIndices) {
  574. throw new Error('Do not supported yet');
  575. }
  576. }
  577. var rawIndex = invertedIndices[value];
  578. if (rawIndex == null || isNaN(rawIndex)) {
  579. return INDEX_NOT_FOUND;
  580. }
  581. return rawIndex;
  582. };
  583. /**
  584. * Retrieve the index of nearest value
  585. * @param dim
  586. * @param value
  587. * @param [maxDistance=Infinity]
  588. * @return If and only if multiple indices has
  589. * the same value, they are put to the result.
  590. */
  591. SeriesData.prototype.indicesOfNearest = function (dim, value, maxDistance) {
  592. return this._store.indicesOfNearest(this._getStoreDimIndex(dim), value, maxDistance);
  593. };
  594. SeriesData.prototype.each = function (dims, cb, ctx) {
  595. 'use strict';
  596. if (zrUtil.isFunction(dims)) {
  597. ctx = cb;
  598. cb = dims;
  599. dims = [];
  600. } // ctxCompat just for compat echarts3
  601. var fCtx = ctx || this;
  602. var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this);
  603. this._store.each(dimIndices, fCtx ? zrUtil.bind(cb, fCtx) : cb);
  604. };
  605. SeriesData.prototype.filterSelf = function (dims, cb, ctx) {
  606. 'use strict';
  607. if (zrUtil.isFunction(dims)) {
  608. ctx = cb;
  609. cb = dims;
  610. dims = [];
  611. } // ctxCompat just for compat echarts3
  612. var fCtx = ctx || this;
  613. var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this);
  614. this._store = this._store.filter(dimIndices, fCtx ? zrUtil.bind(cb, fCtx) : cb);
  615. return this;
  616. };
  617. /**
  618. * Select data in range. (For optimization of filter)
  619. * (Manually inline code, support 5 million data filtering in data zoom.)
  620. */
  621. SeriesData.prototype.selectRange = function (range) {
  622. 'use strict';
  623. var _this = this;
  624. var innerRange = {};
  625. var dims = zrUtil.keys(range);
  626. var dimIndices = [];
  627. zrUtil.each(dims, function (dim) {
  628. var dimIdx = _this._getStoreDimIndex(dim);
  629. innerRange[dimIdx] = range[dim];
  630. dimIndices.push(dimIdx);
  631. });
  632. this._store = this._store.selectRange(innerRange);
  633. return this;
  634. };
  635. /* eslint-enable max-len */
  636. SeriesData.prototype.mapArray = function (dims, cb, ctx) {
  637. 'use strict';
  638. if (zrUtil.isFunction(dims)) {
  639. ctx = cb;
  640. cb = dims;
  641. dims = [];
  642. } // ctxCompat just for compat echarts3
  643. ctx = ctx || this;
  644. var result = [];
  645. this.each(dims, function () {
  646. result.push(cb && cb.apply(this, arguments));
  647. }, ctx);
  648. return result;
  649. };
  650. SeriesData.prototype.map = function (dims, cb, ctx, ctxCompat) {
  651. 'use strict'; // ctxCompat just for compat echarts3
  652. var fCtx = ctx || ctxCompat || this;
  653. var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this);
  654. var list = cloneListForMapAndSample(this);
  655. list._store = this._store.map(dimIndices, fCtx ? zrUtil.bind(cb, fCtx) : cb);
  656. return list;
  657. };
  658. SeriesData.prototype.modify = function (dims, cb, ctx, ctxCompat) {
  659. var _this = this; // ctxCompat just for compat echarts3
  660. var fCtx = ctx || ctxCompat || this;
  661. if (process.env.NODE_ENV !== 'production') {
  662. zrUtil.each(normalizeDimensions(dims), function (dim) {
  663. var dimInfo = _this.getDimensionInfo(dim);
  664. if (!dimInfo.isCalculationCoord) {
  665. console.error('Danger: only stack dimension can be modified');
  666. }
  667. });
  668. }
  669. var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); // If do shallow clone here, if there are too many stacked series,
  670. // it still cost lots of memory, because `_store.dimensions` are not shared.
  671. // We should consider there probably be shallow clone happen in each series
  672. // in consequent filter/map.
  673. this._store.modify(dimIndices, fCtx ? zrUtil.bind(cb, fCtx) : cb);
  674. };
  675. /**
  676. * Large data down sampling on given dimension
  677. * @param sampleIndex Sample index for name and id
  678. */
  679. SeriesData.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) {
  680. var list = cloneListForMapAndSample(this);
  681. list._store = this._store.downSample(this._getStoreDimIndex(dimension), rate, sampleValue, sampleIndex);
  682. return list;
  683. };
  684. /**
  685. * Large data down sampling using largest-triangle-three-buckets
  686. * @param {string} valueDimension
  687. * @param {number} targetCount
  688. */
  689. SeriesData.prototype.lttbDownSample = function (valueDimension, rate) {
  690. var list = cloneListForMapAndSample(this);
  691. list._store = this._store.lttbDownSample(this._getStoreDimIndex(valueDimension), rate);
  692. return list;
  693. };
  694. SeriesData.prototype.getRawDataItem = function (idx) {
  695. return this._store.getRawDataItem(idx);
  696. };
  697. /**
  698. * Get model of one data item.
  699. */
  700. // TODO: Type of data item
  701. SeriesData.prototype.getItemModel = function (idx) {
  702. var hostModel = this.hostModel;
  703. var dataItem = this.getRawDataItem(idx);
  704. return new Model(dataItem, hostModel, hostModel && hostModel.ecModel);
  705. };
  706. /**
  707. * Create a data differ
  708. */
  709. SeriesData.prototype.diff = function (otherList) {
  710. var thisList = this;
  711. return new DataDiffer(otherList ? otherList.getStore().getIndices() : [], this.getStore().getIndices(), function (idx) {
  712. return getId(otherList, idx);
  713. }, function (idx) {
  714. return getId(thisList, idx);
  715. });
  716. };
  717. /**
  718. * Get visual property.
  719. */
  720. SeriesData.prototype.getVisual = function (key) {
  721. var visual = this._visual;
  722. return visual && visual[key];
  723. };
  724. SeriesData.prototype.setVisual = function (kvObj, val) {
  725. this._visual = this._visual || {};
  726. if (isObject(kvObj)) {
  727. zrUtil.extend(this._visual, kvObj);
  728. } else {
  729. this._visual[kvObj] = val;
  730. }
  731. };
  732. /**
  733. * Get visual property of single data item
  734. */
  735. // eslint-disable-next-line
  736. SeriesData.prototype.getItemVisual = function (idx, key) {
  737. var itemVisual = this._itemVisuals[idx];
  738. var val = itemVisual && itemVisual[key];
  739. if (val == null) {
  740. // Use global visual property
  741. return this.getVisual(key);
  742. }
  743. return val;
  744. };
  745. /**
  746. * If exists visual property of single data item
  747. */
  748. SeriesData.prototype.hasItemVisual = function () {
  749. return this._itemVisuals.length > 0;
  750. };
  751. /**
  752. * Make sure itemVisual property is unique
  753. */
  754. // TODO: use key to save visual to reduce memory.
  755. SeriesData.prototype.ensureUniqueItemVisual = function (idx, key) {
  756. var itemVisuals = this._itemVisuals;
  757. var itemVisual = itemVisuals[idx];
  758. if (!itemVisual) {
  759. itemVisual = itemVisuals[idx] = {};
  760. }
  761. var val = itemVisual[key];
  762. if (val == null) {
  763. val = this.getVisual(key); // TODO Performance?
  764. if (zrUtil.isArray(val)) {
  765. val = val.slice();
  766. } else if (isObject(val)) {
  767. val = zrUtil.extend({}, val);
  768. }
  769. itemVisual[key] = val;
  770. }
  771. return val;
  772. }; // eslint-disable-next-line
  773. SeriesData.prototype.setItemVisual = function (idx, key, value) {
  774. var itemVisual = this._itemVisuals[idx] || {};
  775. this._itemVisuals[idx] = itemVisual;
  776. if (isObject(key)) {
  777. zrUtil.extend(itemVisual, key);
  778. } else {
  779. itemVisual[key] = value;
  780. }
  781. };
  782. /**
  783. * Clear itemVisuals and list visual.
  784. */
  785. SeriesData.prototype.clearAllVisual = function () {
  786. this._visual = {};
  787. this._itemVisuals = [];
  788. };
  789. SeriesData.prototype.setLayout = function (key, val) {
  790. isObject(key) ? zrUtil.extend(this._layout, key) : this._layout[key] = val;
  791. };
  792. /**
  793. * Get layout property.
  794. */
  795. SeriesData.prototype.getLayout = function (key) {
  796. return this._layout[key];
  797. };
  798. /**
  799. * Get layout of single data item
  800. */
  801. SeriesData.prototype.getItemLayout = function (idx) {
  802. return this._itemLayouts[idx];
  803. };
  804. /**
  805. * Set layout of single data item
  806. */
  807. SeriesData.prototype.setItemLayout = function (idx, layout, merge) {
  808. this._itemLayouts[idx] = merge ? zrUtil.extend(this._itemLayouts[idx] || {}, layout) : layout;
  809. };
  810. /**
  811. * Clear all layout of single data item
  812. */
  813. SeriesData.prototype.clearItemLayouts = function () {
  814. this._itemLayouts.length = 0;
  815. };
  816. /**
  817. * Set graphic element relative to data. It can be set as null
  818. */
  819. SeriesData.prototype.setItemGraphicEl = function (idx, el) {
  820. var seriesIndex = this.hostModel && this.hostModel.seriesIndex;
  821. setCommonECData(seriesIndex, this.dataType, idx, el);
  822. this._graphicEls[idx] = el;
  823. };
  824. SeriesData.prototype.getItemGraphicEl = function (idx) {
  825. return this._graphicEls[idx];
  826. };
  827. SeriesData.prototype.eachItemGraphicEl = function (cb, context) {
  828. zrUtil.each(this._graphicEls, function (el, idx) {
  829. if (el) {
  830. cb && cb.call(context, el, idx);
  831. }
  832. });
  833. };
  834. /**
  835. * Shallow clone a new list except visual and layout properties, and graph elements.
  836. * New list only change the indices.
  837. */
  838. SeriesData.prototype.cloneShallow = function (list) {
  839. if (!list) {
  840. list = new SeriesData(this._schema ? this._schema : map(this.dimensions, this._getDimInfo, this), this.hostModel);
  841. }
  842. transferProperties(list, this);
  843. list._store = this._store;
  844. return list;
  845. };
  846. /**
  847. * Wrap some method to add more feature
  848. */
  849. SeriesData.prototype.wrapMethod = function (methodName, injectFunction) {
  850. var originalMethod = this[methodName];
  851. if (!zrUtil.isFunction(originalMethod)) {
  852. return;
  853. }
  854. this.__wrappedMethods = this.__wrappedMethods || [];
  855. this.__wrappedMethods.push(methodName);
  856. this[methodName] = function () {
  857. var res = originalMethod.apply(this, arguments);
  858. return injectFunction.apply(this, [res].concat(zrUtil.slice(arguments)));
  859. };
  860. }; // ----------------------------------------------------------
  861. // A work around for internal method visiting private member.
  862. // ----------------------------------------------------------
  863. SeriesData.internalField = function () {
  864. prepareInvertedIndex = function (data) {
  865. var invertedIndicesMap = data._invertedIndicesMap;
  866. zrUtil.each(invertedIndicesMap, function (invertedIndices, dim) {
  867. var dimInfo = data._dimInfos[dim]; // Currently, only dimensions that has ordinalMeta can create inverted indices.
  868. var ordinalMeta = dimInfo.ordinalMeta;
  869. var store = data._store;
  870. if (ordinalMeta) {
  871. invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(ordinalMeta.categories.length); // The default value of TypedArray is 0. To avoid miss
  872. // mapping to 0, we should set it as INDEX_NOT_FOUND.
  873. for (var i = 0; i < invertedIndices.length; i++) {
  874. invertedIndices[i] = INDEX_NOT_FOUND;
  875. }
  876. for (var i = 0; i < store.count(); i++) {
  877. // Only support the case that all values are distinct.
  878. invertedIndices[store.get(dimInfo.storeDimIndex, i)] = i;
  879. }
  880. }
  881. });
  882. };
  883. getIdNameFromStore = function (data, dimIdx, idx) {
  884. return convertOptionIdName(data._getCategory(dimIdx, idx), null);
  885. };
  886. /**
  887. * @see the comment of `List['getId']`.
  888. */
  889. getId = function (data, rawIndex) {
  890. var id = data._idList[rawIndex];
  891. if (id == null && data._idDimIdx != null) {
  892. id = getIdNameFromStore(data, data._idDimIdx, rawIndex);
  893. }
  894. if (id == null) {
  895. id = ID_PREFIX + rawIndex;
  896. }
  897. return id;
  898. };
  899. normalizeDimensions = function (dimensions) {
  900. if (!zrUtil.isArray(dimensions)) {
  901. dimensions = dimensions != null ? [dimensions] : [];
  902. }
  903. return dimensions;
  904. };
  905. /**
  906. * Data in excludeDimensions is copied, otherwise transferred.
  907. */
  908. cloneListForMapAndSample = function (original) {
  909. var list = new SeriesData(original._schema ? original._schema : map(original.dimensions, original._getDimInfo, original), original.hostModel); // FIXME If needs stackedOn, value may already been stacked
  910. transferProperties(list, original);
  911. return list;
  912. };
  913. transferProperties = function (target, source) {
  914. zrUtil.each(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {
  915. if (source.hasOwnProperty(propName)) {
  916. target[propName] = source[propName];
  917. }
  918. });
  919. target.__wrappedMethods = source.__wrappedMethods;
  920. zrUtil.each(CLONE_PROPERTIES, function (propName) {
  921. target[propName] = zrUtil.clone(source[propName]);
  922. });
  923. target._calculationInfo = zrUtil.extend({}, source._calculationInfo);
  924. };
  925. makeIdFromName = function (data, idx) {
  926. var nameList = data._nameList;
  927. var idList = data._idList;
  928. var nameDimIdx = data._nameDimIdx;
  929. var idDimIdx = data._idDimIdx;
  930. var name = nameList[idx];
  931. var id = idList[idx];
  932. if (name == null && nameDimIdx != null) {
  933. nameList[idx] = name = getIdNameFromStore(data, nameDimIdx, idx);
  934. }
  935. if (id == null && idDimIdx != null) {
  936. idList[idx] = id = getIdNameFromStore(data, idDimIdx, idx);
  937. }
  938. if (id == null && name != null) {
  939. var nameRepeatCount = data._nameRepeatCount;
  940. var nmCnt = nameRepeatCount[name] = (nameRepeatCount[name] || 0) + 1;
  941. id = name;
  942. if (nmCnt > 1) {
  943. id += '__ec__' + nmCnt;
  944. }
  945. idList[idx] = id;
  946. }
  947. };
  948. }();
  949. return SeriesData;
  950. }();
  951. export default SeriesData;