import { c3_chart_internal_fn } from './core'; import { isValue, isUndefined, isDefined, notEmpty } from './util'; c3_chart_internal_fn.convertUrlToData = function (url, mimeType, headers, keys, done) { var $$ = this, type = mimeType ? mimeType : 'csv'; var req = $$.d3.request(url); if (headers) { Object.keys(headers).forEach(function (header) { req.header(header, headers[header]); }); } req.get(function (error, data) { var d; var dataResponse = data.response || data.responseText; // Fixes IE9 XHR issue; see #1345 if (!data) { throw new Error(error.responseURL + ' ' + error.status + ' (' + error.statusText + ')'); } if (type === 'json') { d = $$.convertJsonToData(JSON.parse(dataResponse), keys); } else if (type === 'tsv') { d = $$.convertTsvToData(dataResponse); } else { d = $$.convertCsvToData(dataResponse); } done.call($$, d); }); }; c3_chart_internal_fn.convertXsvToData = function (xsv, parser) { var rows = parser(xsv), d; if (rows.length === 1) { d = [{}]; rows[0].forEach(function (id) { d[0][id] = null; }); } else { d = parser(xsv); } return d; }; c3_chart_internal_fn.convertCsvToData = function (csv) { return this.convertXsvToData(csv, this.d3.csvParse); }; c3_chart_internal_fn.convertTsvToData = function (tsv) { return this.convertXsvToData(tsv, this.d3.tsvParse); }; c3_chart_internal_fn.convertJsonToData = function (json, keys) { var $$ = this, new_rows = [], targetKeys, data; if (keys) { // when keys specified, json would be an array that includes objects if (keys.x) { targetKeys = keys.value.concat(keys.x); $$.config.data_x = keys.x; } else { targetKeys = keys.value; } new_rows.push(targetKeys); json.forEach(function (o) { var new_row = []; targetKeys.forEach(function (key) { // convert undefined to null because undefined data will be removed in convertDataToTargets() var v = $$.findValueInJson(o, key); if (isUndefined(v)) { v = null; } new_row.push(v); }); new_rows.push(new_row); }); data = $$.convertRowsToData(new_rows); } else { Object.keys(json).forEach(function (key) { new_rows.push([key].concat(json[key])); }); data = $$.convertColumnsToData(new_rows); } return data; }; c3_chart_internal_fn.findValueInJson = function (object, path) { path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties (replace [] with .) path = path.replace(/^\./, ''); // strip a leading dot var pathArray = path.split('.'); for (var i = 0; i < pathArray.length; ++i) { var k = pathArray[i]; if (k in object) { object = object[k]; } else { return; } } return object; }; /** * Converts the rows to normalized data. * @param {any[][]} rows The row data * @return {Object[]} */ c3_chart_internal_fn.convertRowsToData = (rows) => { const newRows = []; const keys = rows[0]; for (let i = 1; i < rows.length; i++) { const newRow = {}; for (let j = 0; j < rows[i].length; j++) { if (isUndefined(rows[i][j])) { throw new Error("Source data is missing a component at (" + i + "," + j + ")!"); } newRow[keys[j]] = rows[i][j]; } newRows.push(newRow); } return newRows; }; /** * Converts the columns to normalized data. * @param {any[][]} columns The column data * @return {Object[]} */ c3_chart_internal_fn.convertColumnsToData = (columns) => { const newRows = []; for (let i = 0; i < columns.length; i++) { const key = columns[i][0]; for (let j = 1; j < columns[i].length; j++) { if (isUndefined(newRows[j - 1])) { newRows[j - 1] = {}; } if (isUndefined(columns[i][j])) { throw new Error("Source data is missing a component at (" + i + "," + j + ")!"); } newRows[j - 1][key] = columns[i][j]; } } return newRows; }; c3_chart_internal_fn.convertDataToTargets = function (data, appendXs) { var $$ = this, config = $$.config, ids = $$.d3.keys(data[0]).filter($$.isNotX, $$), xs = $$.d3.keys(data[0]).filter($$.isX, $$), targets; // save x for update data by load when custom x and c3.x API ids.forEach(function (id) { var xKey = $$.getXKey(id); if ($$.isCustomX() || $$.isTimeSeries()) { // if included in input data if (xs.indexOf(xKey) >= 0) { $$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat( data.map(function (d) { return d[xKey]; }) .filter(isValue) .map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); }) ); } // if not included in input data, find from preloaded data of other id's x else if (config.data_x) { $$.data.xs[id] = $$.getOtherTargetXs(); } // if not included in input data, find from preloaded data else if (notEmpty(config.data_xs)) { $$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets); } // MEMO: if no x included, use same x of current will be used } else { $$.data.xs[id] = data.map(function (d, i) { return i; }); } }); // check x is defined ids.forEach(function (id) { if (!$$.data.xs[id]) { throw new Error('x is not defined for id = "' + id + '".'); } }); // convert to target targets = ids.map(function (id, index) { var convertedId = config.data_idConverter(id); return { id: convertedId, id_org: id, values: data.map(function (d, i) { var xKey = $$.getXKey(id), rawX = d[xKey], value = d[id] !== null && !isNaN(d[id]) ? +d[id] : null, x; // use x as categories if custom x and categorized if ($$.isCustomX() && $$.isCategorized() && !isUndefined(rawX)) { if (index === 0 && i === 0) { config.axis_x_categories = []; } x = config.axis_x_categories.indexOf(rawX); if (x === -1) { x = config.axis_x_categories.length; config.axis_x_categories.push(rawX); } } else { x = $$.generateTargetX(rawX, id, i); } // mark as x = undefined if value is undefined and filter to remove after mapped if (isUndefined(d[id]) || $$.data.xs[id].length <= i) { x = undefined; } return {x: x, value: value, id: convertedId}; }).filter(function (v) { return isDefined(v.x); }) }; }); // finish targets targets.forEach(function (t) { var i; // sort values by its x if (config.data_xSort) { t.values = t.values.sort(function (v1, v2) { var x1 = v1.x || v1.x === 0 ? v1.x : Infinity, x2 = v2.x || v2.x === 0 ? v2.x : Infinity; return x1 - x2; }); } // indexing each value i = 0; t.values.forEach(function (v) { v.index = i++; }); // this needs to be sorted because its index and value.index is identical $$.data.xs[t.id].sort(function (v1, v2) { return v1 - v2; }); }); // cache information about values $$.hasNegativeValue = $$.hasNegativeValueInTargets(targets); $$.hasPositiveValue = $$.hasPositiveValueInTargets(targets); // set target types if (config.data_type) { $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type); } // cache as original id keyed targets.forEach(function (d) { $$.addCache(d.id_org, d); }); return targets; };