Source.js 11 KB

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