completeDimensions.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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 _util = require("zrender/lib/core/util");
  20. var createHashMap = _util.createHashMap;
  21. var each = _util.each;
  22. var isString = _util.isString;
  23. var defaults = _util.defaults;
  24. var extend = _util.extend;
  25. var isObject = _util.isObject;
  26. var clone = _util.clone;
  27. var _model = require("../../util/model");
  28. var normalizeToArray = _model.normalizeToArray;
  29. var _sourceHelper = require("./sourceHelper");
  30. var guessOrdinal = _sourceHelper.guessOrdinal;
  31. var BE_ORDINAL = _sourceHelper.BE_ORDINAL;
  32. var Source = require("../Source");
  33. var _dimensionHelper = require("./dimensionHelper");
  34. var OTHER_DIMENSIONS = _dimensionHelper.OTHER_DIMENSIONS;
  35. var DataDimensionInfo = require("../DataDimensionInfo");
  36. /*
  37. * Licensed to the Apache Software Foundation (ASF) under one
  38. * or more contributor license agreements. See the NOTICE file
  39. * distributed with this work for additional information
  40. * regarding copyright ownership. The ASF licenses this file
  41. * to you under the Apache License, Version 2.0 (the
  42. * "License"); you may not use this file except in compliance
  43. * with the License. You may obtain a copy of the License at
  44. *
  45. * http://www.apache.org/licenses/LICENSE-2.0
  46. *
  47. * Unless required by applicable law or agreed to in writing,
  48. * software distributed under the License is distributed on an
  49. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  50. * KIND, either express or implied. See the License for the
  51. * specific language governing permissions and limitations
  52. * under the License.
  53. */
  54. /**
  55. * @deprecated
  56. * Use `echarts/data/helper/createDimensions` instead.
  57. */
  58. /**
  59. * @see {module:echarts/test/ut/spec/data/completeDimensions}
  60. *
  61. * This method builds the relationship between:
  62. * + "what the coord sys or series requires (see `sysDims`)",
  63. * + "what the user defines (in `encode` and `dimensions`, see `opt.dimsDef` and `opt.encodeDef`)"
  64. * + "what the data source provids (see `source`)".
  65. *
  66. * Some guess strategy will be adapted if user does not define something.
  67. * If no 'value' dimension specified, the first no-named dimension will be
  68. * named as 'value'.
  69. *
  70. * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which
  71. * provides not only dim template, but also default order.
  72. * properties: 'name', 'type', 'displayName'.
  73. * `name` of each item provides default coord name.
  74. * [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and
  75. * provide dims count that the sysDim required.
  76. * [{ordinalMeta}] can be specified.
  77. * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)
  78. * @param {Object} [opt]
  79. * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions
  80. * For example: ['asdf', {name, type}, ...].
  81. * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}
  82. * @param {Function} [opt.encodeDefaulter] Called if no `opt.encodeDef` exists.
  83. * If not specified, auto find the next available data dim.
  84. * param source {module:data/Source}
  85. * param dimCount {number}
  86. * return {Object} encode Never be `null/undefined`.
  87. * @param {string} [opt.generateCoord] Generate coord dim with the given name.
  88. * If not specified, extra dim names will be:
  89. * 'value', 'value0', 'value1', ...
  90. * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.
  91. * If `generateCoordCount` specified, the generated dim names will be:
  92. * `generateCoord` + 0, `generateCoord` + 1, ...
  93. * can be Infinity, indicate that use all of the remain columns.
  94. * @param {number} [opt.dimCount] If not specified, guess by the first data item.
  95. * @return {Array.<module:data/DataDimensionInfo>}
  96. */
  97. function completeDimensions(sysDims, source, opt) {
  98. if (!Source.isInstance(source)) {
  99. source = Source.seriesDataToSource(source);
  100. }
  101. opt = opt || {};
  102. sysDims = (sysDims || []).slice();
  103. var dimsDef = (opt.dimsDef || []).slice();
  104. var dataDimNameMap = createHashMap();
  105. var coordDimNameMap = createHashMap(); // var valueCandidate;
  106. var result = [];
  107. var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount); // Apply user defined dims (`name` and `type`) and init result.
  108. for (var i = 0; i < dimCount; i++) {
  109. var dimDefItem = dimsDef[i] = extend({}, isObject(dimsDef[i]) ? dimsDef[i] : {
  110. name: dimsDef[i]
  111. });
  112. var userDimName = dimDefItem.name;
  113. var resultItem = result[i] = new DataDimensionInfo(); // Name will be applied later for avoiding duplication.
  114. if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
  115. // Only if `series.dimensions` is defined in option
  116. // displayName, will be set, and dimension will be diplayed vertically in
  117. // tooltip by default.
  118. resultItem.name = resultItem.displayName = userDimName;
  119. dataDimNameMap.set(userDimName, i);
  120. }
  121. dimDefItem.type != null && (resultItem.type = dimDefItem.type);
  122. dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
  123. }
  124. var encodeDef = opt.encodeDef;
  125. if (!encodeDef && opt.encodeDefaulter) {
  126. encodeDef = opt.encodeDefaulter(source, dimCount);
  127. }
  128. encodeDef = createHashMap(encodeDef); // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.
  129. encodeDef.each(function (dataDims, coordDim) {
  130. dataDims = normalizeToArray(dataDims).slice(); // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
  131. // `{encode: {x: -1, y: 1}}`. Should not filter anything in
  132. // this case.
  133. if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
  134. encodeDef.set(coordDim, false);
  135. return;
  136. }
  137. var validDataDims = encodeDef.set(coordDim, []);
  138. each(dataDims, function (resultDimIdx, idx) {
  139. // The input resultDimIdx can be dim name or index.
  140. isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));
  141. if (resultDimIdx != null && resultDimIdx < dimCount) {
  142. validDataDims[idx] = resultDimIdx;
  143. applyDim(result[resultDimIdx], coordDim, idx);
  144. }
  145. });
  146. }); // Apply templetes and default order from `sysDims`.
  147. var availDimIdx = 0;
  148. each(sysDims, function (sysDimItem, sysDimIndex) {
  149. var coordDim;
  150. var sysDimItem;
  151. var sysDimItemDimsDef;
  152. var sysDimItemOtherDims;
  153. if (isString(sysDimItem)) {
  154. coordDim = sysDimItem;
  155. sysDimItem = {};
  156. } else {
  157. coordDim = sysDimItem.name;
  158. var ordinalMeta = sysDimItem.ordinalMeta;
  159. sysDimItem.ordinalMeta = null;
  160. sysDimItem = clone(sysDimItem);
  161. sysDimItem.ordinalMeta = ordinalMeta; // `coordDimIndex` should not be set directly.
  162. sysDimItemDimsDef = sysDimItem.dimsDef;
  163. sysDimItemOtherDims = sysDimItem.otherDims;
  164. sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null;
  165. }
  166. var dataDims = encodeDef.get(coordDim); // negative resultDimIdx means no need to mapping.
  167. if (dataDims === false) {
  168. return;
  169. }
  170. var dataDims = normalizeToArray(dataDims); // dimensions provides default dim sequences.
  171. if (!dataDims.length) {
  172. for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
  173. while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {
  174. availDimIdx++;
  175. }
  176. availDimIdx < result.length && dataDims.push(availDimIdx++);
  177. }
  178. } // Apply templates.
  179. each(dataDims, function (resultDimIdx, coordDimIndex) {
  180. var resultItem = result[resultDimIdx];
  181. applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
  182. if (resultItem.name == null && sysDimItemDimsDef) {
  183. var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
  184. !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {
  185. name: sysDimItemDimsDefItem
  186. });
  187. resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
  188. resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
  189. } // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
  190. sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
  191. });
  192. });
  193. function applyDim(resultItem, coordDim, coordDimIndex) {
  194. if (OTHER_DIMENSIONS.get(coordDim) != null) {
  195. resultItem.otherDims[coordDim] = coordDimIndex;
  196. } else {
  197. resultItem.coordDim = coordDim;
  198. resultItem.coordDimIndex = coordDimIndex;
  199. coordDimNameMap.set(coordDim, true);
  200. }
  201. } // Make sure the first extra dim is 'value'.
  202. var generateCoord = opt.generateCoord;
  203. var generateCoordCount = opt.generateCoordCount;
  204. var fromZero = generateCoordCount != null;
  205. generateCoordCount = generateCoord ? generateCoordCount || 1 : 0;
  206. var extra = generateCoord || 'value'; // Set dim `name` and other `coordDim` and other props.
  207. for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
  208. var resultItem = result[resultDimIdx] = result[resultDimIdx] || new DataDimensionInfo();
  209. var coordDim = resultItem.coordDim;
  210. if (coordDim == null) {
  211. resultItem.coordDim = genName(extra, coordDimNameMap, fromZero);
  212. resultItem.coordDimIndex = 0;
  213. if (!generateCoord || generateCoordCount <= 0) {
  214. resultItem.isExtraCoord = true;
  215. }
  216. generateCoordCount--;
  217. }
  218. resultItem.name == null && (resultItem.name = genName(resultItem.coordDim, dataDimNameMap));
  219. if (resultItem.type == null && (guessOrdinal(source, resultDimIdx, resultItem.name) === BE_ORDINAL.Must // Consider the case:
  220. // {
  221. // dataset: {source: [
  222. // ['2001', 123],
  223. // ['2002', 456],
  224. // ...
  225. // ['The others', 987],
  226. // ]},
  227. // series: {type: 'pie'}
  228. // }
  229. // The first colum should better be treated as a "ordinal" although it
  230. // might not able to be detected as an "ordinal" by `guessOrdinal`.
  231. || resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) {
  232. resultItem.type = 'ordinal';
  233. }
  234. }
  235. return result;
  236. } // ??? TODO
  237. // Originally detect dimCount by data[0]. Should we
  238. // optimize it to only by sysDims and dimensions and encode.
  239. // So only necessary dims will be initialized.
  240. // But
  241. // (1) custom series should be considered. where other dims
  242. // may be visited.
  243. // (2) sometimes user need to calcualte bubble size or use visualMap
  244. // on other dimensions besides coordSys needed.
  245. // So, dims that is not used by system, should be shared in storage?
  246. function getDimCount(source, sysDims, dimsDef, optDimCount) {
  247. // Note that the result dimCount should not small than columns count
  248. // of data, otherwise `dataDimNameMap` checking will be incorrect.
  249. var dimCount = Math.max(source.dimensionsDetectCount || 1, sysDims.length, dimsDef.length, optDimCount || 0);
  250. each(sysDims, function (sysDimItem) {
  251. var sysDimItemDimsDef = sysDimItem.dimsDef;
  252. sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));
  253. });
  254. return dimCount;
  255. }
  256. function genName(name, map, fromZero) {
  257. if (fromZero || map.get(name) != null) {
  258. var i = 0;
  259. while (map.get(name + i) != null) {
  260. i++;
  261. }
  262. name += i;
  263. }
  264. map.set(name, true);
  265. return name;
  266. }
  267. var _default = completeDimensions;
  268. module.exports = _default;