mirror of https://github.com/masayuki0812/c3.git
Quite good looking graph derived from d3.js
http://c3js.org
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
8.4 KiB
248 lines
8.4 KiB
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; |
|
};
|
|
|