MatrixDim.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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. import { createHashMap, defaults, each, eqNaN, isArray, isObject, isString } from 'zrender/lib/core/util.js';
  41. import Point from 'zrender/lib/core/Point.js';
  42. import OrdinalMeta from '../../data/OrdinalMeta.js';
  43. import Ordinal from '../../scale/Ordinal.js';
  44. import { WH, XY } from '../../util/graphic.js';
  45. import { ListIterator } from '../../util/model.js';
  46. import { createNaNRectLike, setDimXYValue, MatrixCellLayoutInfoType } from './matrixCoordHelper.js';
  47. import { error } from '../../util/log.js';
  48. import { mathMax } from '../../util/number.js';
  49. /**
  50. * Lifetime: the same with `MatrixModel`, but different from `coord/Matrix`.
  51. */
  52. var MatrixDim = /** @class */function () {
  53. function MatrixDim(dim, dimModel) {
  54. // Under the current definition, every leave corresponds a unit cell,
  55. // and leaves can serve as the locator of cells.
  56. // Therefore make sure:
  57. // - The first `_leavesCount` elements in `_cells` are leaves.
  58. // - `_cells[leaf.id[XY[this.dimIdx]]]` is the leaf itself.
  59. // - Leaves of each subtree are placed together, that is, the leaves of a dimCell are:
  60. // `this._cells.slice(dimCell.firstLeafLocator, dimCell.span[XY[this.dimIdx]])`
  61. this._cells = [];
  62. // Can be visited by `_levels[cell.level]` or `_levels[cell.id[1 - dimIdx] + _levels.length]`.
  63. // Items are never be null/undefined after initialized.
  64. this._levels = [];
  65. this.dim = dim;
  66. this.dimIdx = dim === 'x' ? 0 : 1;
  67. this._model = dimModel;
  68. this._uniqueValueGen = createUniqueValueGenerator(dim);
  69. var dimModelData = dimModel.get('data', true);
  70. if (dimModelData != null && !isArray(dimModelData)) {
  71. if (process.env.NODE_ENV !== 'production') {
  72. error("Illegal echarts option - matrix." + this.dim + ".data must be an array if specified.");
  73. }
  74. dimModelData = [];
  75. }
  76. if (dimModelData) {
  77. this._initByDimModelData(dimModelData);
  78. } else {
  79. this._initBySeriesData();
  80. }
  81. }
  82. MatrixDim.prototype._initByDimModelData = function (dimModelData) {
  83. var self = this;
  84. var _cells = self._cells;
  85. var _levels = self._levels;
  86. var sameLocatorCellsLists = []; // Save for sorting.
  87. var _cellCount = 0;
  88. self._leavesCount = traverseInitCells(dimModelData, 0, 0);
  89. postInitCells();
  90. return;
  91. function traverseInitCells(dimModelData, firstLeafLocator, level) {
  92. var totalSpan = 0;
  93. if (!dimModelData) {
  94. return totalSpan;
  95. }
  96. each(dimModelData, function (option, optionIdx) {
  97. var invalidOption = false;
  98. var cellOption;
  99. if (isString(option)) {
  100. cellOption = {
  101. value: option
  102. };
  103. } else if (isObject(option)) {
  104. cellOption = option;
  105. if (option.value != null && !isString(option.value)) {
  106. invalidOption = true;
  107. cellOption = {
  108. value: null
  109. };
  110. }
  111. } else {
  112. cellOption = {
  113. value: null
  114. };
  115. if (option != null) {
  116. invalidOption = true;
  117. }
  118. }
  119. if (invalidOption) {
  120. if (process.env.NODE_ENV !== 'production') {
  121. error("Illegal echarts option - matrix." + self.dim + ".data[" + optionIdx + "]" + ' must be `string | {value: string}`.');
  122. }
  123. }
  124. var cell = {
  125. type: MatrixCellLayoutInfoType.nonLeaf,
  126. ordinal: NaN,
  127. level: level,
  128. firstLeafLocator: firstLeafLocator,
  129. id: new Point(),
  130. span: setDimXYValue(new Point(), self.dimIdx, 1, 1),
  131. option: cellOption,
  132. xy: NaN,
  133. wh: NaN,
  134. dim: self,
  135. rect: createNaNRectLike()
  136. };
  137. _cellCount++;
  138. (sameLocatorCellsLists[firstLeafLocator] || (sameLocatorCellsLists[firstLeafLocator] = [])).push(cell);
  139. if (!_levels[level]) {
  140. // Create a level only if at least one cell exists.
  141. _levels[level] = {
  142. type: MatrixCellLayoutInfoType.level,
  143. xy: NaN,
  144. wh: NaN,
  145. option: null,
  146. id: new Point(),
  147. dim: self
  148. };
  149. }
  150. var childrenSpan = traverseInitCells(cellOption.children, firstLeafLocator, level + 1);
  151. var subSpan = Math.max(1, childrenSpan);
  152. cell.span[XY[self.dimIdx]] = subSpan;
  153. totalSpan += subSpan;
  154. firstLeafLocator += subSpan;
  155. });
  156. return totalSpan;
  157. }
  158. function postInitCells() {
  159. // Sort to make sure the leaves are at the beginning, so that
  160. // they can be used as the locator of body cells.
  161. var categories = [];
  162. while (_cells.length < _cellCount) {
  163. for (var locator = 0; locator < sameLocatorCellsLists.length; locator++) {
  164. var cell = sameLocatorCellsLists[locator].pop();
  165. if (cell) {
  166. cell.ordinal = categories.length;
  167. var val = cell.option.value;
  168. categories.push(val);
  169. _cells.push(cell);
  170. self._uniqueValueGen.calcDupBase(val);
  171. }
  172. }
  173. }
  174. self._uniqueValueGen.ensureValueUnique(categories, _cells);
  175. var ordinalMeta = self._ordinalMeta = new OrdinalMeta({
  176. categories: categories,
  177. needCollect: false,
  178. deduplication: false
  179. });
  180. self._scale = new Ordinal({
  181. ordinalMeta: ordinalMeta
  182. });
  183. for (var idx = 0; idx < self._leavesCount; idx++) {
  184. var leaf = self._cells[idx];
  185. leaf.type = MatrixCellLayoutInfoType.leaf;
  186. // Handle the tree level variation: enlarge the span of the leaves to reach the body cells.
  187. leaf.span[XY[1 - self.dimIdx]] = self._levels.length - leaf.level;
  188. }
  189. self._initCellsId();
  190. self._initLevelIdOptions();
  191. }
  192. };
  193. MatrixDim.prototype._initBySeriesData = function () {
  194. var self = this;
  195. self._leavesCount = 0;
  196. self._levels = [{
  197. type: MatrixCellLayoutInfoType.level,
  198. xy: NaN,
  199. wh: NaN,
  200. option: null,
  201. id: new Point(),
  202. dim: self
  203. }];
  204. self._initLevelIdOptions();
  205. var ordinalMeta = self._ordinalMeta = new OrdinalMeta({
  206. needCollect: true,
  207. deduplication: true,
  208. onCollect: function (value, ordinalNumber) {
  209. var cell = self._cells[ordinalNumber] = {
  210. type: MatrixCellLayoutInfoType.leaf,
  211. ordinal: ordinalNumber,
  212. level: 0,
  213. firstLeafLocator: ordinalNumber,
  214. id: new Point(),
  215. span: setDimXYValue(new Point(), self.dimIdx, 1, 1),
  216. // Theoretically `value` is from `dataset` or `series.data`, so it may be any type.
  217. // Do not restrict this case for user's convenience, and here simply convert it to
  218. // string for display.
  219. option: {
  220. value: value + ''
  221. },
  222. xy: NaN,
  223. wh: NaN,
  224. dim: self,
  225. rect: createNaNRectLike()
  226. };
  227. self._leavesCount++;
  228. self._setCellId(cell);
  229. }
  230. });
  231. self._scale = new Ordinal({
  232. ordinalMeta: ordinalMeta
  233. });
  234. };
  235. MatrixDim.prototype._setCellId = function (cell) {
  236. var levelsLen = this._levels.length;
  237. var dimIdx = this.dimIdx;
  238. setDimXYValue(cell.id, dimIdx, cell.firstLeafLocator, cell.level - levelsLen);
  239. };
  240. MatrixDim.prototype._initCellsId = function () {
  241. var levelsLen = this._levels.length;
  242. var dimIdx = this.dimIdx;
  243. each(this._cells, function (cell) {
  244. setDimXYValue(cell.id, dimIdx, cell.firstLeafLocator, cell.level - levelsLen);
  245. });
  246. };
  247. MatrixDim.prototype._initLevelIdOptions = function () {
  248. var levelsLen = this._levels.length;
  249. var dimIdx = this.dimIdx;
  250. var levelOptionList = this._model.get('levels', true);
  251. levelOptionList = isArray(levelOptionList) ? levelOptionList : [];
  252. each(this._levels, function (levelCfg, level) {
  253. setDimXYValue(levelCfg.id, dimIdx, 0, level - levelsLen);
  254. levelCfg.option = levelOptionList[level];
  255. });
  256. };
  257. MatrixDim.prototype.shouldShow = function () {
  258. return !!this._model.getShallow('show', true);
  259. };
  260. /**
  261. * Iterate leaves (they are layout units) if dimIdx === this.dimIdx.
  262. * Iterate levels if dimIdx !== this.dimIdx.
  263. */
  264. MatrixDim.prototype.resetLayoutIterator = function (it, dimIdx, startLocator, count) {
  265. it = it || new ListIterator();
  266. if (dimIdx === this.dimIdx) {
  267. var len = this._leavesCount;
  268. var startIdx = startLocator != null ? Math.max(0, startLocator) : 0;
  269. count = count != null ? Math.min(count, len) : len;
  270. it.reset(this._cells, startIdx, startIdx + count);
  271. } else {
  272. var len = this._levels.length;
  273. // Corner locator is from `-this._levels.length` to `-1`.
  274. var startIdx = startLocator != null ? Math.max(0, startLocator + len) : 0;
  275. count = count != null ? Math.min(count, len) : len;
  276. it.reset(this._levels, startIdx, startIdx + count);
  277. }
  278. return it;
  279. };
  280. MatrixDim.prototype.resetCellIterator = function (it) {
  281. return (it || new ListIterator()).reset(this._cells, 0);
  282. };
  283. MatrixDim.prototype.resetLevelIterator = function (it) {
  284. return (it || new ListIterator()).reset(this._levels, 0);
  285. };
  286. MatrixDim.prototype.getLayout = function (outRect, dimIdx, locator) {
  287. var layout = this.getUnitLayoutInfo(dimIdx, locator);
  288. outRect[XY[dimIdx]] = layout ? layout.xy : NaN;
  289. outRect[WH[dimIdx]] = layout ? layout.wh : NaN;
  290. };
  291. /**
  292. * Get leaf cell or get level info.
  293. * Should be able to return null/undefined if not found on x or y, thus input `dimIdx` is needed.
  294. */
  295. MatrixDim.prototype.getUnitLayoutInfo = function (dimIdx, locator) {
  296. return dimIdx === this.dimIdx ? locator < this._leavesCount ? this._cells[locator] : undefined : this._levels[locator + this._levels.length];
  297. };
  298. /**
  299. * Get dimension cell by data, including leaves and non-leaves.
  300. */
  301. MatrixDim.prototype.getCell = function (value) {
  302. var ordinal = this._scale.parse(value);
  303. return eqNaN(ordinal) ? undefined : this._cells[ordinal];
  304. };
  305. /**
  306. * Get leaf count or get level count.
  307. */
  308. MatrixDim.prototype.getLocatorCount = function (dimIdx) {
  309. return dimIdx === this.dimIdx ? this._leavesCount : this._levels.length;
  310. };
  311. MatrixDim.prototype.getOrdinalMeta = function () {
  312. return this._ordinalMeta;
  313. };
  314. return MatrixDim;
  315. }();
  316. export { MatrixDim };
  317. function createUniqueValueGenerator(dim) {
  318. var dimUpper = dim.toUpperCase();
  319. var defaultValReg = new RegExp("^" + dimUpper + "([0-9]+)$");
  320. var dupBase = 0;
  321. function calcDupBase(val) {
  322. var matchResult;
  323. if (val != null && (matchResult = val.match(defaultValReg))) {
  324. dupBase = mathMax(dupBase, +matchResult[1] + 1);
  325. }
  326. }
  327. function makeUniqueValue() {
  328. return "" + dimUpper + dupBase++;
  329. }
  330. // Duplicated value is allowed, because the `matrix.x/y.data` can be a tree and it's reasonable
  331. // that leaves in different subtrees has the same text. But only the first one is allowed to be
  332. // queried by the text, and the other ones can only be queried by index.
  333. // Additionally, `matrix.x/y.data: [null, null, ...]` is allowed.
  334. function ensureValueUnique(categories, cells) {
  335. // A simple way to deduplicate or handle illegal or not specified values to avoid unexpected behaviors.
  336. // The tree structure should not be broken even if duplicated.
  337. var cateMap = createHashMap();
  338. for (var idx = 0; idx < categories.length; idx++) {
  339. var value = categories[idx];
  340. // value may be set to NullUndefined by users or if illegal.
  341. if (value == null || cateMap.get(value) != null) {
  342. // Still display the original option.value if duplicated, but loose the ability to query by text.
  343. categories[idx] = value = makeUniqueValue();
  344. cells[idx].option = defaults({
  345. value: value
  346. }, cells[idx].option);
  347. }
  348. cateMap.set(value, true);
  349. }
  350. }
  351. return {
  352. calcDupBase: calcDupBase,
  353. ensureValueUnique: ensureValueUnique
  354. };
  355. }