2
0

data.convert.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import { c3_chart_internal_fn } from './core';
  2. import { isValue, isUndefined, isDefined, notEmpty } from './util';
  3. c3_chart_internal_fn.convertUrlToData = function (url, mimeType, headers, keys, done) {
  4. var $$ = this, type = mimeType ? mimeType : 'csv';
  5. var req = $$.d3.request(url);
  6. if (headers) {
  7. Object.keys(headers).forEach(function (header) {
  8. req.header(header, headers[header]);
  9. });
  10. }
  11. req.get(function (error, data) {
  12. var d;
  13. var dataResponse = data.response || data.responseText; // Fixes IE9 XHR issue; see #1345
  14. if (!data) {
  15. throw new Error(error.responseURL + ' ' + error.status + ' (' + error.statusText + ')');
  16. }
  17. if (type === 'json') {
  18. d = $$.convertJsonToData(JSON.parse(dataResponse), keys);
  19. } else if (type === 'tsv') {
  20. d = $$.convertTsvToData(dataResponse);
  21. } else {
  22. d = $$.convertCsvToData(dataResponse);
  23. }
  24. done.call($$, d);
  25. });
  26. };
  27. c3_chart_internal_fn.convertXsvToData = function (xsv, parser) {
  28. var rows = parser(xsv), d;
  29. if (rows.length === 1) {
  30. d = [{}];
  31. rows[0].forEach(function (id) {
  32. d[0][id] = null;
  33. });
  34. } else {
  35. d = parser(xsv);
  36. }
  37. return d;
  38. };
  39. c3_chart_internal_fn.convertCsvToData = function (csv) {
  40. return this.convertXsvToData(csv, this.d3.csvParse);
  41. };
  42. c3_chart_internal_fn.convertTsvToData = function (tsv) {
  43. return this.convertXsvToData(tsv, this.d3.tsvParse);
  44. };
  45. c3_chart_internal_fn.convertJsonToData = function (json, keys) {
  46. var $$ = this,
  47. new_rows = [], targetKeys, data;
  48. if (keys) { // when keys specified, json would be an array that includes objects
  49. if (keys.x) {
  50. targetKeys = keys.value.concat(keys.x);
  51. $$.config.data_x = keys.x;
  52. } else {
  53. targetKeys = keys.value;
  54. }
  55. new_rows.push(targetKeys);
  56. json.forEach(function (o) {
  57. var new_row = [];
  58. targetKeys.forEach(function (key) {
  59. // convert undefined to null because undefined data will be removed in convertDataToTargets()
  60. var v = $$.findValueInJson(o, key);
  61. if (isUndefined(v)) {
  62. v = null;
  63. }
  64. new_row.push(v);
  65. });
  66. new_rows.push(new_row);
  67. });
  68. data = $$.convertRowsToData(new_rows);
  69. } else {
  70. Object.keys(json).forEach(function (key) {
  71. new_rows.push([key].concat(json[key]));
  72. });
  73. data = $$.convertColumnsToData(new_rows);
  74. }
  75. return data;
  76. };
  77. c3_chart_internal_fn.findValueInJson = function (object, path) {
  78. path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties (replace [] with .)
  79. path = path.replace(/^\./, ''); // strip a leading dot
  80. var pathArray = path.split('.');
  81. for (var i = 0; i < pathArray.length; ++i) {
  82. var k = pathArray[i];
  83. if (k in object) {
  84. object = object[k];
  85. } else {
  86. return;
  87. }
  88. }
  89. return object;
  90. };
  91. /**
  92. * Converts the rows to normalized data.
  93. * @param {any[][]} rows The row data
  94. * @return {Object[]}
  95. */
  96. c3_chart_internal_fn.convertRowsToData = (rows) => {
  97. const newRows = [];
  98. const keys = rows[0];
  99. for (let i = 1; i < rows.length; i++) {
  100. const newRow = {};
  101. for (let j = 0; j < rows[i].length; j++) {
  102. if (isUndefined(rows[i][j])) {
  103. throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
  104. }
  105. newRow[keys[j]] = rows[i][j];
  106. }
  107. newRows.push(newRow);
  108. }
  109. return newRows;
  110. };
  111. /**
  112. * Converts the columns to normalized data.
  113. * @param {any[][]} columns The column data
  114. * @return {Object[]}
  115. */
  116. c3_chart_internal_fn.convertColumnsToData = (columns) => {
  117. const newRows = [];
  118. for (let i = 0; i < columns.length; i++) {
  119. const key = columns[i][0];
  120. for (let j = 1; j < columns[i].length; j++) {
  121. if (isUndefined(newRows[j - 1])) {
  122. newRows[j - 1] = {};
  123. }
  124. if (isUndefined(columns[i][j])) {
  125. throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
  126. }
  127. newRows[j - 1][key] = columns[i][j];
  128. }
  129. }
  130. return newRows;
  131. };
  132. c3_chart_internal_fn.convertDataToTargets = function (data, appendXs) {
  133. var $$ = this, config = $$.config,
  134. ids = $$.d3.keys(data[0]).filter($$.isNotX, $$),
  135. xs = $$.d3.keys(data[0]).filter($$.isX, $$),
  136. targets;
  137. // save x for update data by load when custom x and c3.x API
  138. ids.forEach(function (id) {
  139. var xKey = $$.getXKey(id);
  140. if ($$.isCustomX() || $$.isTimeSeries()) {
  141. // if included in input data
  142. if (xs.indexOf(xKey) >= 0) {
  143. $$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat(
  144. data.map(function (d) { return d[xKey]; })
  145. .filter(isValue)
  146. .map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); })
  147. );
  148. }
  149. // if not included in input data, find from preloaded data of other id's x
  150. else if (config.data_x) {
  151. $$.data.xs[id] = $$.getOtherTargetXs();
  152. }
  153. // if not included in input data, find from preloaded data
  154. else if (notEmpty(config.data_xs)) {
  155. $$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets);
  156. }
  157. // MEMO: if no x included, use same x of current will be used
  158. } else {
  159. $$.data.xs[id] = data.map(function (d, i) { return i; });
  160. }
  161. });
  162. // check x is defined
  163. ids.forEach(function (id) {
  164. if (!$$.data.xs[id]) {
  165. throw new Error('x is not defined for id = "' + id + '".');
  166. }
  167. });
  168. // convert to target
  169. targets = ids.map(function (id, index) {
  170. var convertedId = config.data_idConverter(id);
  171. return {
  172. id: convertedId,
  173. id_org: id,
  174. values: data.map(function (d, i) {
  175. var xKey = $$.getXKey(id), rawX = d[xKey],
  176. value = d[id] !== null && !isNaN(d[id]) ? +d[id] : null, x;
  177. // use x as categories if custom x and categorized
  178. if ($$.isCustomX() && $$.isCategorized() && !isUndefined(rawX)) {
  179. if (index === 0 && i === 0) {
  180. config.axis_x_categories = [];
  181. }
  182. x = config.axis_x_categories.indexOf(rawX);
  183. if (x === -1) {
  184. x = config.axis_x_categories.length;
  185. config.axis_x_categories.push(rawX);
  186. }
  187. } else {
  188. x = $$.generateTargetX(rawX, id, i);
  189. }
  190. // mark as x = undefined if value is undefined and filter to remove after mapped
  191. if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
  192. x = undefined;
  193. }
  194. return {x: x, value: value, id: convertedId};
  195. }).filter(function (v) { return isDefined(v.x); })
  196. };
  197. });
  198. // finish targets
  199. targets.forEach(function (t) {
  200. var i;
  201. // sort values by its x
  202. if (config.data_xSort) {
  203. t.values = t.values.sort(function (v1, v2) {
  204. var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
  205. x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
  206. return x1 - x2;
  207. });
  208. }
  209. // indexing each value
  210. i = 0;
  211. t.values.forEach(function (v) {
  212. v.index = i++;
  213. });
  214. // this needs to be sorted because its index and value.index is identical
  215. $$.data.xs[t.id].sort(function (v1, v2) {
  216. return v1 - v2;
  217. });
  218. });
  219. // cache information about values
  220. $$.hasNegativeValue = $$.hasNegativeValueInTargets(targets);
  221. $$.hasPositiveValue = $$.hasPositiveValueInTargets(targets);
  222. // set target types
  223. if (config.data_type) {
  224. $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type);
  225. }
  226. // cache as original id keyed
  227. targets.forEach(function (d) {
  228. $$.addCache(d.id_org, d);
  229. });
  230. return targets;
  231. };