createDimensions.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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 { VISUAL_DIMENSIONS } from '../../util/types.js';
  41. import SeriesDimensionDefine from '../SeriesDimensionDefine.js';
  42. import { createHashMap, defaults, each, extend, isObject, isString } from 'zrender/lib/core/util.js';
  43. import { createSourceFromSeriesDataOption, isSourceInstance } from '../Source.js';
  44. import { CtorInt32Array } from '../DataStore.js';
  45. import { normalizeToArray } from '../../util/model.js';
  46. import { BE_ORDINAL, guessOrdinal } from './sourceHelper.js';
  47. import { createDimNameMap, ensureSourceDimNameMap, SeriesDataSchema, shouldOmitUnusedDimensions } from './SeriesDataSchema.js';
  48. /**
  49. * For outside usage compat (like echarts-gl are using it).
  50. */
  51. export function createDimensions(source, opt) {
  52. return prepareSeriesDataSchema(source, opt).dimensions;
  53. }
  54. /**
  55. * This method builds the relationship between:
  56. * + "what the coord sys or series requires (see `coordDimensions`)",
  57. * + "what the user defines (in `encode` and `dimensions`, see `opt.dimensionsDefine` and `opt.encodeDefine`)"
  58. * + "what the data source provids (see `source`)".
  59. *
  60. * Some guess strategy will be adapted if user does not define something.
  61. * If no 'value' dimension specified, the first no-named dimension will be
  62. * named as 'value'.
  63. *
  64. * @return The results are always sorted by `storeDimIndex` asc.
  65. */
  66. export default function prepareSeriesDataSchema( // TODO: TYPE completeDimensions type
  67. source, opt) {
  68. if (!isSourceInstance(source)) {
  69. source = createSourceFromSeriesDataOption(source);
  70. }
  71. opt = opt || {};
  72. var sysDims = opt.coordDimensions || [];
  73. var dimsDef = opt.dimensionsDefine || source.dimensionsDefine || [];
  74. var coordDimNameMap = createHashMap();
  75. var resultList = [];
  76. var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimensionsCount); // Try to ignore unused dimensions if sharing a high dimension datastore
  77. // 30 is an experience value.
  78. var omitUnusedDimensions = opt.canOmitUnusedDimensions && shouldOmitUnusedDimensions(dimCount);
  79. var isUsingSourceDimensionsDef = dimsDef === source.dimensionsDefine;
  80. var dataDimNameMap = isUsingSourceDimensionsDef ? ensureSourceDimNameMap(source) : createDimNameMap(dimsDef);
  81. var encodeDef = opt.encodeDefine;
  82. if (!encodeDef && opt.encodeDefaulter) {
  83. encodeDef = opt.encodeDefaulter(source, dimCount);
  84. }
  85. var encodeDefMap = createHashMap(encodeDef);
  86. var indicesMap = new CtorInt32Array(dimCount);
  87. for (var i = 0; i < indicesMap.length; i++) {
  88. indicesMap[i] = -1;
  89. }
  90. function getResultItem(dimIdx) {
  91. var idx = indicesMap[dimIdx];
  92. if (idx < 0) {
  93. var dimDefItemRaw = dimsDef[dimIdx];
  94. var dimDefItem = isObject(dimDefItemRaw) ? dimDefItemRaw : {
  95. name: dimDefItemRaw
  96. };
  97. var resultItem = new SeriesDimensionDefine();
  98. var userDimName = dimDefItem.name;
  99. if (userDimName != null && dataDimNameMap.get(userDimName) != null) {
  100. // Only if `series.dimensions` is defined in option
  101. // displayName, will be set, and dimension will be displayed vertically in
  102. // tooltip by default.
  103. resultItem.name = resultItem.displayName = userDimName;
  104. }
  105. dimDefItem.type != null && (resultItem.type = dimDefItem.type);
  106. dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
  107. var newIdx = resultList.length;
  108. indicesMap[dimIdx] = newIdx;
  109. resultItem.storeDimIndex = dimIdx;
  110. resultList.push(resultItem);
  111. return resultItem;
  112. }
  113. return resultList[idx];
  114. }
  115. if (!omitUnusedDimensions) {
  116. for (var i = 0; i < dimCount; i++) {
  117. getResultItem(i);
  118. }
  119. } // Set `coordDim` and `coordDimIndex` by `encodeDefMap` and normalize `encodeDefMap`.
  120. encodeDefMap.each(function (dataDimsRaw, coordDim) {
  121. var dataDims = normalizeToArray(dataDimsRaw).slice(); // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
  122. // `{encode: {x: -1, y: 1}}`. Should not filter anything in
  123. // this case.
  124. if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
  125. encodeDefMap.set(coordDim, false);
  126. return;
  127. }
  128. var validDataDims = encodeDefMap.set(coordDim, []);
  129. each(dataDims, function (resultDimIdxOrName, idx) {
  130. // The input resultDimIdx can be dim name or index.
  131. var resultDimIdx = isString(resultDimIdxOrName) ? dataDimNameMap.get(resultDimIdxOrName) : resultDimIdxOrName;
  132. if (resultDimIdx != null && resultDimIdx < dimCount) {
  133. validDataDims[idx] = resultDimIdx;
  134. applyDim(getResultItem(resultDimIdx), coordDim, idx);
  135. }
  136. });
  137. }); // Apply templates and default order from `sysDims`.
  138. var availDimIdx = 0;
  139. each(sysDims, function (sysDimItemRaw) {
  140. var coordDim;
  141. var sysDimItemDimsDef;
  142. var sysDimItemOtherDims;
  143. var sysDimItem;
  144. if (isString(sysDimItemRaw)) {
  145. coordDim = sysDimItemRaw;
  146. sysDimItem = {};
  147. } else {
  148. sysDimItem = sysDimItemRaw;
  149. coordDim = sysDimItem.name;
  150. var ordinalMeta = sysDimItem.ordinalMeta;
  151. sysDimItem.ordinalMeta = null;
  152. sysDimItem = extend({}, sysDimItem);
  153. sysDimItem.ordinalMeta = ordinalMeta; // `coordDimIndex` should not be set directly.
  154. sysDimItemDimsDef = sysDimItem.dimsDef;
  155. sysDimItemOtherDims = sysDimItem.otherDims;
  156. sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null;
  157. }
  158. var dataDims = encodeDefMap.get(coordDim); // negative resultDimIdx means no need to mapping.
  159. if (dataDims === false) {
  160. return;
  161. }
  162. dataDims = normalizeToArray(dataDims); // dimensions provides default dim sequences.
  163. if (!dataDims.length) {
  164. for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
  165. while (availDimIdx < dimCount && getResultItem(availDimIdx).coordDim != null) {
  166. availDimIdx++;
  167. }
  168. availDimIdx < dimCount && dataDims.push(availDimIdx++);
  169. }
  170. } // Apply templates.
  171. each(dataDims, function (resultDimIdx, coordDimIndex) {
  172. var resultItem = getResultItem(resultDimIdx); // Coordinate system has a higher priority on dim type than source.
  173. if (isUsingSourceDimensionsDef && sysDimItem.type != null) {
  174. resultItem.type = sysDimItem.type;
  175. }
  176. applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
  177. if (resultItem.name == null && sysDimItemDimsDef) {
  178. var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
  179. !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {
  180. name: sysDimItemDimsDefItem
  181. });
  182. resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
  183. resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
  184. } // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
  185. sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
  186. });
  187. });
  188. function applyDim(resultItem, coordDim, coordDimIndex) {
  189. if (VISUAL_DIMENSIONS.get(coordDim) != null) {
  190. resultItem.otherDims[coordDim] = coordDimIndex;
  191. } else {
  192. resultItem.coordDim = coordDim;
  193. resultItem.coordDimIndex = coordDimIndex;
  194. coordDimNameMap.set(coordDim, true);
  195. }
  196. } // Make sure the first extra dim is 'value'.
  197. var generateCoord = opt.generateCoord;
  198. var generateCoordCount = opt.generateCoordCount;
  199. var fromZero = generateCoordCount != null;
  200. generateCoordCount = generateCoord ? generateCoordCount || 1 : 0;
  201. var extra = generateCoord || 'value';
  202. function ifNoNameFillWithCoordName(resultItem) {
  203. if (resultItem.name == null) {
  204. // Duplication will be removed in the next step.
  205. resultItem.name = resultItem.coordDim;
  206. }
  207. } // Set dim `name` and other `coordDim` and other props.
  208. if (!omitUnusedDimensions) {
  209. for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
  210. var resultItem = getResultItem(resultDimIdx);
  211. var coordDim = resultItem.coordDim;
  212. if (coordDim == null) {
  213. // TODO no need to generate coordDim for isExtraCoord?
  214. resultItem.coordDim = genCoordDimName(extra, coordDimNameMap, fromZero);
  215. resultItem.coordDimIndex = 0; // Series specified generateCoord is using out.
  216. if (!generateCoord || generateCoordCount <= 0) {
  217. resultItem.isExtraCoord = true;
  218. }
  219. generateCoordCount--;
  220. }
  221. ifNoNameFillWithCoordName(resultItem);
  222. if (resultItem.type == null && (guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must // Consider the case:
  223. // {
  224. // dataset: {source: [
  225. // ['2001', 123],
  226. // ['2002', 456],
  227. // ...
  228. // ['The others', 987],
  229. // ]},
  230. // series: {type: 'pie'}
  231. // }
  232. // The first column should better be treated as a "ordinal" although it
  233. // might not be detected as an "ordinal" by `guessOrdinal`.
  234. || resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) {
  235. resultItem.type = 'ordinal';
  236. }
  237. }
  238. } else {
  239. each(resultList, function (resultItem) {
  240. // PENDING: guessOrdinal or let user specify type: 'ordinal' manually?
  241. ifNoNameFillWithCoordName(resultItem);
  242. }); // Sort dimensions: there are some rule that use the last dim as label,
  243. // and for some latter travel process easier.
  244. resultList.sort(function (item0, item1) {
  245. return item0.storeDimIndex - item1.storeDimIndex;
  246. });
  247. }
  248. removeDuplication(resultList);
  249. return new SeriesDataSchema({
  250. source: source,
  251. dimensions: resultList,
  252. fullDimensionCount: dimCount,
  253. dimensionOmitted: omitUnusedDimensions
  254. });
  255. }
  256. function removeDuplication(result) {
  257. var duplicationMap = createHashMap();
  258. for (var i = 0; i < result.length; i++) {
  259. var dim = result[i];
  260. var dimOriginalName = dim.name;
  261. var count = duplicationMap.get(dimOriginalName) || 0;
  262. if (count > 0) {
  263. // Starts from 0.
  264. dim.name = dimOriginalName + (count - 1);
  265. }
  266. count++;
  267. duplicationMap.set(dimOriginalName, count);
  268. }
  269. } // ??? TODO
  270. // Originally detect dimCount by data[0]. Should we
  271. // optimize it to only by sysDims and dimensions and encode.
  272. // So only necessary dims will be initialized.
  273. // But
  274. // (1) custom series should be considered. where other dims
  275. // may be visited.
  276. // (2) sometimes user need to calculate bubble size or use visualMap
  277. // on other dimensions besides coordSys needed.
  278. // So, dims that is not used by system, should be shared in data store?
  279. function getDimCount(source, sysDims, dimsDef, optDimCount) {
  280. // Note that the result dimCount should not small than columns count
  281. // of data, otherwise `dataDimNameMap` checking will be incorrect.
  282. var dimCount = Math.max(source.dimensionsDetectedCount || 1, sysDims.length, dimsDef.length, optDimCount || 0);
  283. each(sysDims, function (sysDimItem) {
  284. var sysDimItemDimsDef;
  285. if (isObject(sysDimItem) && (sysDimItemDimsDef = sysDimItem.dimsDef)) {
  286. dimCount = Math.max(dimCount, sysDimItemDimsDef.length);
  287. }
  288. });
  289. return dimCount;
  290. }
  291. function genCoordDimName(name, map, fromZero) {
  292. if (fromZero || map.hasKey(name)) {
  293. var i = 0;
  294. while (map.hasKey(name + i)) {
  295. i++;
  296. }
  297. name += i;
  298. }
  299. map.set(name, true);
  300. return name;
  301. }