Source.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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 { isTypedArray, clone, createHashMap, isArray, isObject, isArrayLike, hasOwn, assert, each, map, isNumber, isString, keys } from 'zrender/lib/core/util.js';
  41. import { SOURCE_FORMAT_ORIGINAL, SERIES_LAYOUT_BY_COLUMN, SOURCE_FORMAT_UNKNOWN, SOURCE_FORMAT_KEYED_COLUMNS, SOURCE_FORMAT_TYPED_ARRAY, SOURCE_FORMAT_ARRAY_ROWS, SOURCE_FORMAT_OBJECT_ROWS, SERIES_LAYOUT_BY_ROW } from '../util/types.js';
  42. import { getDataItemValue } from '../util/model.js';
  43. import { BE_ORDINAL, guessOrdinal } from './helper/sourceHelper.js';
  44. ;
  45. // @inner
  46. var SourceImpl = /** @class */function () {
  47. function SourceImpl(fields) {
  48. this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []);
  49. this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;
  50. // Visit config
  51. this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;
  52. this.startIndex = fields.startIndex || 0;
  53. this.dimensionsDetectedCount = fields.dimensionsDetectedCount;
  54. this.metaRawOption = fields.metaRawOption;
  55. var dimensionsDefine = this.dimensionsDefine = fields.dimensionsDefine;
  56. if (dimensionsDefine) {
  57. for (var i = 0; i < dimensionsDefine.length; i++) {
  58. var dim = dimensionsDefine[i];
  59. if (dim.type == null) {
  60. if (guessOrdinal(this, i) === BE_ORDINAL.Must) {
  61. dim.type = 'ordinal';
  62. }
  63. }
  64. }
  65. }
  66. }
  67. return SourceImpl;
  68. }();
  69. export function isSourceInstance(val) {
  70. return val instanceof SourceImpl;
  71. }
  72. /**
  73. * Create a source from option.
  74. * NOTE: Created source is immutable. Don't change any properties in it.
  75. */
  76. export function createSource(sourceData, thisMetaRawOption,
  77. // can be null. If not provided, auto detect it from `sourceData`.
  78. sourceFormat) {
  79. sourceFormat = sourceFormat || detectSourceFormat(sourceData);
  80. var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy;
  81. var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions);
  82. var source = new SourceImpl({
  83. data: sourceData,
  84. sourceFormat: sourceFormat,
  85. seriesLayoutBy: seriesLayoutBy,
  86. dimensionsDefine: determined.dimensionsDefine,
  87. startIndex: determined.startIndex,
  88. dimensionsDetectedCount: determined.dimensionsDetectedCount,
  89. metaRawOption: clone(thisMetaRawOption)
  90. });
  91. return source;
  92. }
  93. /**
  94. * Wrap original series data for some compatibility cases.
  95. */
  96. export function createSourceFromSeriesDataOption(data) {
  97. return new SourceImpl({
  98. data: data,
  99. sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL
  100. });
  101. }
  102. /**
  103. * Clone source but excludes source data.
  104. */
  105. export function cloneSourceShallow(source) {
  106. return new SourceImpl({
  107. data: source.data,
  108. sourceFormat: source.sourceFormat,
  109. seriesLayoutBy: source.seriesLayoutBy,
  110. dimensionsDefine: clone(source.dimensionsDefine),
  111. startIndex: source.startIndex,
  112. dimensionsDetectedCount: source.dimensionsDetectedCount
  113. });
  114. }
  115. /**
  116. * Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`.
  117. */
  118. export function detectSourceFormat(data) {
  119. var sourceFormat = SOURCE_FORMAT_UNKNOWN;
  120. if (isTypedArray(data)) {
  121. sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;
  122. } else if (isArray(data)) {
  123. // FIXME Whether tolerate null in top level array?
  124. if (data.length === 0) {
  125. sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
  126. }
  127. for (var i = 0, len = data.length; i < len; i++) {
  128. var item = data[i];
  129. if (item == null) {
  130. continue;
  131. } else if (isArray(item) || isTypedArray(item)) {
  132. sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
  133. break;
  134. } else if (isObject(item)) {
  135. sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;
  136. break;
  137. }
  138. }
  139. } else if (isObject(data)) {
  140. for (var key in data) {
  141. if (hasOwn(data, key) && isArrayLike(data[key])) {
  142. sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;
  143. break;
  144. }
  145. }
  146. }
  147. return sourceFormat;
  148. }
  149. /**
  150. * Determine the source definitions from data standalone dimensions definitions
  151. * are not specified.
  152. */
  153. function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader,
  154. // standalone raw dimensions definition, like:
  155. // {
  156. // dimensions: ['aa', 'bb', { name: 'cc', type: 'time' }]
  157. // }
  158. // in `dataset` or `series`
  159. dimensionsDefine) {
  160. var dimensionsDetectedCount;
  161. var startIndex;
  162. // PENDING: Could data be null/undefined here?
  163. // currently, if `dataset.source` not specified, error thrown.
  164. // if `series.data` not specified, nothing rendered without error thrown.
  165. // Should test these cases.
  166. if (!data) {
  167. return {
  168. dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
  169. startIndex: startIndex,
  170. dimensionsDetectedCount: dimensionsDetectedCount
  171. };
  172. }
  173. if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
  174. var dataArrayRows = data;
  175. // Rule: Most of the first line are string: it is header.
  176. // Caution: consider a line with 5 string and 1 number,
  177. // it still can not be sure it is a head, because the
  178. // 5 string may be 5 values of category columns.
  179. if (sourceHeader === 'auto' || sourceHeader == null) {
  180. arrayRowsTravelFirst(function (val) {
  181. // '-' is regarded as null/undefined.
  182. if (val != null && val !== '-') {
  183. if (isString(val)) {
  184. startIndex == null && (startIndex = 1);
  185. } else {
  186. startIndex = 0;
  187. }
  188. }
  189. // 10 is an experience number, avoid long loop.
  190. }, seriesLayoutBy, dataArrayRows, 10);
  191. } else {
  192. startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0;
  193. }
  194. if (!dimensionsDefine && startIndex === 1) {
  195. dimensionsDefine = [];
  196. arrayRowsTravelFirst(function (val, index) {
  197. dimensionsDefine[index] = val != null ? val + '' : '';
  198. }, seriesLayoutBy, dataArrayRows, Infinity);
  199. }
  200. dimensionsDetectedCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null;
  201. } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
  202. if (!dimensionsDefine) {
  203. dimensionsDefine = objectRowsCollectDimensions(data);
  204. }
  205. } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
  206. if (!dimensionsDefine) {
  207. dimensionsDefine = [];
  208. each(data, function (colArr, key) {
  209. dimensionsDefine.push(key);
  210. });
  211. }
  212. } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
  213. var value0 = getDataItemValue(data[0]);
  214. dimensionsDetectedCount = isArray(value0) && value0.length || 1;
  215. } else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
  216. if (process.env.NODE_ENV !== 'production') {
  217. assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');
  218. }
  219. }
  220. return {
  221. startIndex: startIndex,
  222. dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
  223. dimensionsDetectedCount: dimensionsDetectedCount
  224. };
  225. }
  226. function objectRowsCollectDimensions(data) {
  227. var firstIndex = 0;
  228. var obj;
  229. while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line
  230. if (obj) {
  231. return keys(obj);
  232. }
  233. }
  234. // Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],
  235. // which is reasonable. But dimension name is duplicated.
  236. // Returns undefined or an array contains only object without null/undefined or string.
  237. function normalizeDimensionsOption(dimensionsDefine) {
  238. if (!dimensionsDefine) {
  239. // The meaning of null/undefined is different from empty array.
  240. return;
  241. }
  242. var nameMap = createHashMap();
  243. return map(dimensionsDefine, function (rawItem, index) {
  244. rawItem = isObject(rawItem) ? rawItem : {
  245. name: rawItem
  246. };
  247. // Other fields will be discarded.
  248. var item = {
  249. name: rawItem.name,
  250. displayName: rawItem.displayName,
  251. type: rawItem.type
  252. };
  253. // User can set null in dimensions.
  254. // We don't auto specify name, otherwise a given name may
  255. // cause it to be referred unexpectedly.
  256. if (item.name == null) {
  257. return item;
  258. }
  259. // Also consider number form like 2012.
  260. item.name += '';
  261. // User may also specify displayName.
  262. // displayName will always exists except user not
  263. // specified or dim name is not specified or detected.
  264. // (A auto generated dim name will not be used as
  265. // displayName).
  266. if (item.displayName == null) {
  267. item.displayName = item.name;
  268. }
  269. var exist = nameMap.get(item.name);
  270. if (!exist) {
  271. nameMap.set(item.name, {
  272. count: 1
  273. });
  274. } else {
  275. item.name += '-' + exist.count++;
  276. }
  277. return item;
  278. });
  279. }
  280. function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {
  281. if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {
  282. for (var i = 0; i < data.length && i < maxLoop; i++) {
  283. cb(data[i] ? data[i][0] : null, i);
  284. }
  285. } else {
  286. var value0 = data[0] || [];
  287. for (var i = 0; i < value0.length && i < maxLoop; i++) {
  288. cb(value0[i], i);
  289. }
  290. }
  291. }
  292. export function shouldRetrieveDataByName(source) {
  293. var sourceFormat = source.sourceFormat;
  294. return sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS;
  295. }